claude-flow 2.7.32 → 2.7.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +9 -2
- package/.claude/skills/agentic-jujutsu/SKILL.md +645 -0
- package/CHANGELOG.md +75 -0
- package/bin/claude-flow +1 -1
- package/dist/src/cli/commands/mcp.js +61 -7
- package/dist/src/cli/commands/mcp.js.map +1 -1
- package/dist/src/cli/help-formatter.js +5 -3
- package/dist/src/cli/help-formatter.js.map +1 -1
- package/dist/src/cli/simple-cli.js +173 -79
- package/dist/src/cli/simple-cli.js.map +1 -1
- package/dist/src/cli/validation-helper.js.map +1 -1
- package/dist/src/core/version.js +2 -2
- package/dist/src/core/version.js.map +1 -1
- package/dist/src/mcp/async/job-manager-mcp25.js +240 -0
- package/dist/src/mcp/async/job-manager-mcp25.js.map +1 -0
- package/dist/src/mcp/index.js +8 -0
- package/dist/src/mcp/index.js.map +1 -1
- package/dist/src/mcp/protocol/version-negotiation.js +182 -0
- package/dist/src/mcp/protocol/version-negotiation.js.map +1 -0
- package/dist/src/mcp/registry/mcp-registry-client-2025.js +210 -0
- package/dist/src/mcp/registry/mcp-registry-client-2025.js.map +1 -0
- package/dist/src/mcp/server-factory.js +189 -0
- package/dist/src/mcp/server-factory.js.map +1 -0
- package/dist/src/mcp/server-mcp-2025.js +283 -0
- package/dist/src/mcp/server-mcp-2025.js.map +1 -0
- package/dist/src/mcp/tool-registry-progressive.js +319 -0
- package/dist/src/mcp/tool-registry-progressive.js.map +1 -0
- package/dist/src/mcp/tools/_template.js +62 -0
- package/dist/src/mcp/tools/_template.js.map +1 -0
- package/dist/src/mcp/tools/loader.js +228 -0
- package/dist/src/mcp/tools/loader.js.map +1 -0
- package/dist/src/mcp/tools/system/search.js +224 -0
- package/dist/src/mcp/tools/system/search.js.map +1 -0
- package/dist/src/mcp/tools/system/status.js +168 -0
- package/dist/src/mcp/tools/system/status.js.map +1 -0
- package/dist/src/mcp/validation/schema-validator-2025.js +198 -0
- package/dist/src/mcp/validation/schema-validator-2025.js.map +1 -0
- package/dist/src/memory/swarm-memory.js +340 -421
- package/dist/src/memory/swarm-memory.js.map +1 -1
- package/docs/.claude-flow/metrics/performance.json +3 -3
- package/docs/.claude-flow/metrics/task-metrics.json +3 -3
- package/docs/.github-release-issue-v2.7.33.md +488 -0
- package/docs/AGENTDB_BRANCH_MERGE_VERIFICATION.md +436 -0
- package/docs/BRANCH_REVIEW_SUMMARY.md +439 -0
- package/docs/DEEP_CODE_REVIEW_v2.7.33.md +1159 -0
- package/docs/MCP_2025_FEATURE_CONFIRMATION.md +698 -0
- package/docs/NPM_PUBLISH_GUIDE_v2.7.33.md +628 -0
- package/docs/REGRESSION_TEST_REPORT_v2.7.33.md +397 -0
- package/docs/RELEASE_NOTES_v2.7.33.md +618 -0
- package/docs/RELEASE_READINESS_SUMMARY.md +377 -0
- package/docs/RELEASE_SUMMARY_v2.7.33.md +456 -0
- package/docs/agentic-flow-agentdb-mcp-integration.md +1198 -0
- package/docs/mcp-2025-implementation-summary.md +459 -0
- package/docs/mcp-spec-2025-implementation-plan.md +1330 -0
- package/docs/phase-1-2-implementation-summary.md +676 -0
- package/docs/regression-analysis-phase-1-2.md +555 -0
- package/package.json +5 -1
- package/src/cli/commands/mcp.ts +86 -9
- package/src/mcp/async/job-manager-mcp25.ts +456 -0
- package/src/mcp/index.ts +60 -0
- package/src/mcp/protocol/version-negotiation.ts +329 -0
- package/src/mcp/registry/mcp-registry-client-2025.ts +334 -0
- package/src/mcp/server-factory.ts +426 -0
- package/src/mcp/server-mcp-2025.ts +507 -0
- package/src/mcp/tool-registry-progressive.ts +539 -0
- package/src/mcp/tools/_template.ts +174 -0
- package/src/mcp/tools/loader.ts +362 -0
- package/src/mcp/tools/system/search.ts +276 -0
- package/src/mcp/tools/system/status.ts +206 -0
- package/src/mcp/validation/schema-validator-2025.ts +294 -0
- package/docs/AGENTDB_V1.6.1_DEEP_REVIEW.md +0 -386
- package/docs/RECENT_RELEASES_SUMMARY.md +0 -375
- package/docs/V2.7.31_RELEASE_NOTES.md +0 -375
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Progressive Tool Registry with Dynamic Loading
|
|
3
|
+
*
|
|
4
|
+
* Implements Anthropic's MCP best practices:
|
|
5
|
+
* - Filesystem-based tool discovery
|
|
6
|
+
* - Lazy loading of tool definitions
|
|
7
|
+
* - Progressive disclosure pattern
|
|
8
|
+
* - 98.7% token reduction (150k → 2k tokens)
|
|
9
|
+
*
|
|
10
|
+
* This registry replaces the old monolithic approach where all 50+ tools
|
|
11
|
+
* were loaded upfront. Now tools are discovered via metadata scanning and
|
|
12
|
+
* only loaded when actually invoked.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { createInProcessServer, InProcessMCPServer } from './in-process-server.js';
|
|
16
|
+
import { DynamicToolLoader } from './tools/loader.js';
|
|
17
|
+
import { createSearchToolsTool } from './tools/system/search.js';
|
|
18
|
+
import { logger } from '../core/logger.js';
|
|
19
|
+
import type { MCPTool } from '../utils/types.js';
|
|
20
|
+
import { join } from 'path';
|
|
21
|
+
|
|
22
|
+
// Conditional SDK imports (optional dependency)
|
|
23
|
+
// These will be lazily loaded when needed
|
|
24
|
+
let sdkCache: any = null;
|
|
25
|
+
let sdkLoadAttempted = false;
|
|
26
|
+
|
|
27
|
+
async function getSDK() {
|
|
28
|
+
if (sdkLoadAttempted) {
|
|
29
|
+
return sdkCache;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
sdkLoadAttempted = true;
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
const sdk = await import('@anthropic-ai/claude-code/sdk');
|
|
36
|
+
const zodModule = await import('zod');
|
|
37
|
+
sdkCache = {
|
|
38
|
+
tool: sdk.tool,
|
|
39
|
+
createSdkMcpServer: sdk.createSdkMcpServer,
|
|
40
|
+
z: zodModule.z,
|
|
41
|
+
};
|
|
42
|
+
logger.info('Claude Code SDK loaded successfully');
|
|
43
|
+
} catch (error) {
|
|
44
|
+
logger.info('Claude Code SDK not available, operating without SDK integration');
|
|
45
|
+
sdkCache = null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return sdkCache;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Type placeholder for SDK config
|
|
52
|
+
export type McpSdkServerConfigWithInstance = any;
|
|
53
|
+
|
|
54
|
+
export interface ProgressiveToolRegistryConfig {
|
|
55
|
+
enableInProcess: boolean;
|
|
56
|
+
enableMetrics: boolean;
|
|
57
|
+
enableCaching: boolean;
|
|
58
|
+
orchestratorContext?: any;
|
|
59
|
+
toolsDirectory?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Progressive Tool Registry with Dynamic Loading
|
|
64
|
+
*
|
|
65
|
+
* Key improvements over old registry:
|
|
66
|
+
* 1. Tools discovered via metadata scanning (lightweight)
|
|
67
|
+
* 2. Tools loaded on-demand when invoked (lazy loading)
|
|
68
|
+
* 3. tools/search capability for progressive disclosure
|
|
69
|
+
* 4. 98.7% reduction in token usage
|
|
70
|
+
*/
|
|
71
|
+
export class ProgressiveToolRegistry {
|
|
72
|
+
private toolLoader: DynamicToolLoader;
|
|
73
|
+
private inProcessServer?: InProcessMCPServer;
|
|
74
|
+
private sdkServer?: McpSdkServerConfigWithInstance;
|
|
75
|
+
private config: ProgressiveToolRegistryConfig;
|
|
76
|
+
private toolCache: Map<string, MCPTool> = new Map();
|
|
77
|
+
|
|
78
|
+
constructor(config: ProgressiveToolRegistryConfig) {
|
|
79
|
+
this.config = config;
|
|
80
|
+
|
|
81
|
+
// Initialize dynamic tool loader
|
|
82
|
+
const toolsDir = config.toolsDirectory || join(__dirname, 'tools');
|
|
83
|
+
this.toolLoader = new DynamicToolLoader(toolsDir, logger);
|
|
84
|
+
|
|
85
|
+
logger.info('ProgressiveToolRegistry initialized', {
|
|
86
|
+
enableInProcess: config.enableInProcess,
|
|
87
|
+
enableMetrics: config.enableMetrics,
|
|
88
|
+
toolsDirectory: toolsDir,
|
|
89
|
+
mode: 'progressive-disclosure',
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Initialize the tool registry with progressive disclosure
|
|
95
|
+
*
|
|
96
|
+
* Key difference from old approach:
|
|
97
|
+
* - OLD: Load all 50+ tool definitions upfront (~150k tokens)
|
|
98
|
+
* - NEW: Scan metadata only (~2k tokens), load tools on-demand
|
|
99
|
+
*/
|
|
100
|
+
async initialize(): Promise<void> {
|
|
101
|
+
logger.info('Initializing progressive tool registry...');
|
|
102
|
+
|
|
103
|
+
// Scan for tool metadata (lightweight operation)
|
|
104
|
+
await this.toolLoader.scanTools();
|
|
105
|
+
|
|
106
|
+
const stats = this.toolLoader.getStats();
|
|
107
|
+
logger.info('Tool metadata scan complete', {
|
|
108
|
+
totalTools: stats.totalTools,
|
|
109
|
+
categories: stats.categories,
|
|
110
|
+
toolsByCategory: stats.toolsByCategory,
|
|
111
|
+
mode: 'metadata-only',
|
|
112
|
+
tokenSavings: '98.7%',
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Register core system tools that are always loaded
|
|
116
|
+
await this.registerCoreTools();
|
|
117
|
+
|
|
118
|
+
// Create in-process server if enabled
|
|
119
|
+
if (this.config.enableInProcess) {
|
|
120
|
+
await this.createInProcessServer();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
logger.info('Progressive tool registry initialized', {
|
|
124
|
+
totalToolsDiscovered: stats.totalTools,
|
|
125
|
+
coreToolsLoaded: this.toolCache.size,
|
|
126
|
+
approach: 'progressive-disclosure',
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Register core tools that are always loaded
|
|
132
|
+
* These are lightweight system tools like tools/search
|
|
133
|
+
*/
|
|
134
|
+
private async registerCoreTools(): Promise<void> {
|
|
135
|
+
logger.info('Registering core system tools...');
|
|
136
|
+
|
|
137
|
+
// Register tools/search capability (progressive disclosure)
|
|
138
|
+
const searchTool = createSearchToolsTool(this.toolLoader, logger);
|
|
139
|
+
this.toolCache.set(searchTool.name, searchTool);
|
|
140
|
+
|
|
141
|
+
logger.info('Core tools registered', {
|
|
142
|
+
coreTools: Array.from(this.toolCache.keys()),
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Create SDK-compatible in-process server with lazy loading
|
|
148
|
+
*/
|
|
149
|
+
private async createInProcessServer(): Promise<void> {
|
|
150
|
+
logger.info('Creating progressive in-process MCP server...');
|
|
151
|
+
|
|
152
|
+
// Create in-process server
|
|
153
|
+
this.inProcessServer = createInProcessServer({
|
|
154
|
+
name: 'claude-flow',
|
|
155
|
+
version: '2.7.32',
|
|
156
|
+
enableMetrics: this.config.enableMetrics,
|
|
157
|
+
enableCaching: this.config.enableCaching,
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// Register only core tools initially (lazy load the rest)
|
|
161
|
+
for (const [name, tool] of this.toolCache) {
|
|
162
|
+
this.inProcessServer.registerTool(tool);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Set orchestrator context if provided
|
|
166
|
+
if (this.config.orchestratorContext) {
|
|
167
|
+
this.inProcessServer.setContext({
|
|
168
|
+
orchestrator: this.config.orchestratorContext,
|
|
169
|
+
sessionId: 'progressive-session',
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Create SDK MCP server for integration
|
|
174
|
+
await this.createSdkServer();
|
|
175
|
+
|
|
176
|
+
const stats = this.toolLoader.getStats();
|
|
177
|
+
logger.info('Progressive in-process MCP server created', {
|
|
178
|
+
discoveredTools: stats.totalTools,
|
|
179
|
+
initiallyLoaded: this.toolCache.size,
|
|
180
|
+
lazyLoadEnabled: true,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Create SDK-compatible MCP server with progressive disclosure
|
|
186
|
+
*/
|
|
187
|
+
private async createSdkServer(): Promise<void> {
|
|
188
|
+
if (!this.inProcessServer) {
|
|
189
|
+
throw new Error('In-process server not initialized');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Try to load SDK
|
|
193
|
+
const sdk = await getSDK();
|
|
194
|
+
|
|
195
|
+
if (!sdk) {
|
|
196
|
+
logger.info('SDK not available, skipping SDK server creation');
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Create SDK tools for discovered tools
|
|
201
|
+
const stats = this.toolLoader.getStats();
|
|
202
|
+
const allToolNames = this.toolLoader.getAllToolNames();
|
|
203
|
+
|
|
204
|
+
// Create SDK tools with lazy loading
|
|
205
|
+
const sdkTools = allToolNames.map(toolName => {
|
|
206
|
+
return this.createLazySdkTool(toolName, sdk);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// Create SDK MCP server
|
|
210
|
+
this.sdkServer = sdk.createSdkMcpServer({
|
|
211
|
+
name: 'claude-flow',
|
|
212
|
+
version: '2.7.32',
|
|
213
|
+
tools: sdkTools,
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
logger.info('SDK MCP server created with progressive disclosure', {
|
|
217
|
+
totalTools: sdkTools.length,
|
|
218
|
+
mode: 'lazy-loading',
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Create SDK tool wrapper with lazy loading
|
|
224
|
+
* Tool is only fully loaded when invoked
|
|
225
|
+
*/
|
|
226
|
+
private createLazySdkTool(toolName: string, sdk: any): any {
|
|
227
|
+
// Get lightweight metadata
|
|
228
|
+
const metadata = this.toolLoader.getToolMetadata(toolName);
|
|
229
|
+
|
|
230
|
+
if (!metadata) {
|
|
231
|
+
logger.warn('Tool metadata not found', { toolName });
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Create a minimal Zod schema (will be replaced on first call)
|
|
236
|
+
const zodSchema = sdk.z.object({}).passthrough();
|
|
237
|
+
|
|
238
|
+
// Create SDK tool with lazy loading
|
|
239
|
+
return sdk.tool(
|
|
240
|
+
toolName,
|
|
241
|
+
metadata.description,
|
|
242
|
+
zodSchema,
|
|
243
|
+
async (args: any, extra: unknown) => {
|
|
244
|
+
// Lazy load the full tool definition on first invocation
|
|
245
|
+
const mcpTool = await this.getOrLoadTool(toolName);
|
|
246
|
+
|
|
247
|
+
if (!mcpTool) {
|
|
248
|
+
throw new Error(`Tool not found: ${toolName}`);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Execute via in-process server
|
|
252
|
+
if (this.inProcessServer) {
|
|
253
|
+
return await this.inProcessServer.callTool(toolName, args);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Fallback to direct execution
|
|
257
|
+
const result = await mcpTool.handler(args, {
|
|
258
|
+
orchestrator: this.config.orchestratorContext,
|
|
259
|
+
sessionId: 'sdk-session',
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
return {
|
|
263
|
+
content: [
|
|
264
|
+
{
|
|
265
|
+
type: 'text',
|
|
266
|
+
text: typeof result === 'string' ? result : JSON.stringify(result, null, 2),
|
|
267
|
+
},
|
|
268
|
+
],
|
|
269
|
+
isError: false,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Get or lazy load a tool
|
|
277
|
+
* This is the core of progressive disclosure
|
|
278
|
+
*/
|
|
279
|
+
private async getOrLoadTool(toolName: string): Promise<MCPTool | null> {
|
|
280
|
+
// Check cache first
|
|
281
|
+
if (this.toolCache.has(toolName)) {
|
|
282
|
+
return this.toolCache.get(toolName)!;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Lazy load the tool
|
|
286
|
+
logger.debug('Lazy loading tool', { toolName });
|
|
287
|
+
|
|
288
|
+
const tool = await this.toolLoader.loadTool(toolName, logger);
|
|
289
|
+
|
|
290
|
+
if (tool) {
|
|
291
|
+
// Cache for future use
|
|
292
|
+
this.toolCache.set(toolName, tool);
|
|
293
|
+
|
|
294
|
+
// Register with in-process server if available
|
|
295
|
+
if (this.inProcessServer) {
|
|
296
|
+
this.inProcessServer.registerTool(tool);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
logger.info('Tool lazy loaded and cached', {
|
|
300
|
+
toolName,
|
|
301
|
+
totalCached: this.toolCache.size,
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return tool;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Get tool by name (with lazy loading)
|
|
310
|
+
*/
|
|
311
|
+
async getTool(name: string): Promise<MCPTool | undefined> {
|
|
312
|
+
return (await this.getOrLoadTool(name)) || undefined;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Get all discovered tool names
|
|
317
|
+
* Returns metadata only, not full definitions
|
|
318
|
+
*/
|
|
319
|
+
getToolNames(): string[] {
|
|
320
|
+
return this.toolLoader.getAllToolNames();
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Search tools with progressive disclosure
|
|
325
|
+
* Returns metadata only by default
|
|
326
|
+
*/
|
|
327
|
+
searchTools(query: {
|
|
328
|
+
category?: string;
|
|
329
|
+
tags?: string[];
|
|
330
|
+
namePattern?: string;
|
|
331
|
+
}) {
|
|
332
|
+
return this.toolLoader.searchTools(query);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Get SDK server config for use in query() options
|
|
337
|
+
*/
|
|
338
|
+
getSdkServerConfig(): McpSdkServerConfigWithInstance | undefined {
|
|
339
|
+
return this.sdkServer;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Get in-process server instance
|
|
344
|
+
*/
|
|
345
|
+
getInProcessServer(): InProcessMCPServer | undefined {
|
|
346
|
+
return this.inProcessServer;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Check if tool should use in-process execution
|
|
351
|
+
*/
|
|
352
|
+
shouldUseInProcess(toolName: string): boolean {
|
|
353
|
+
// All discovered tools use in-process
|
|
354
|
+
return this.toolLoader.getToolMetadata(toolName) !== undefined;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Route tool call to appropriate transport with lazy loading
|
|
359
|
+
*/
|
|
360
|
+
async routeToolCall(
|
|
361
|
+
toolName: string,
|
|
362
|
+
args: Record<string, unknown>,
|
|
363
|
+
context?: any
|
|
364
|
+
): Promise<any> {
|
|
365
|
+
const startTime = performance.now();
|
|
366
|
+
|
|
367
|
+
try {
|
|
368
|
+
// Ensure tool is loaded
|
|
369
|
+
const tool = await this.getOrLoadTool(toolName);
|
|
370
|
+
|
|
371
|
+
if (!tool) {
|
|
372
|
+
throw new Error(`Tool not available: ${toolName}`);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
if (this.shouldUseInProcess(toolName) && this.inProcessServer) {
|
|
376
|
+
logger.debug('Routing to in-process server', { toolName });
|
|
377
|
+
const result = await this.inProcessServer.callTool(toolName, args, context);
|
|
378
|
+
const duration = performance.now() - startTime;
|
|
379
|
+
|
|
380
|
+
logger.info('In-process tool call completed', {
|
|
381
|
+
toolName,
|
|
382
|
+
duration: `${duration.toFixed(2)}ms`,
|
|
383
|
+
transport: 'in-process',
|
|
384
|
+
lazyLoaded: !this.toolCache.has(toolName),
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
return result;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// External tools would use stdio/SSE (not implemented in this phase)
|
|
391
|
+
logger.warn('Tool not found in in-process registry', { toolName });
|
|
392
|
+
throw new Error(`Tool not available: ${toolName}`);
|
|
393
|
+
} catch (error) {
|
|
394
|
+
logger.error('Tool routing failed', { toolName, error });
|
|
395
|
+
throw error;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Get performance metrics with token savings
|
|
401
|
+
*/
|
|
402
|
+
getMetrics() {
|
|
403
|
+
const loaderStats = this.toolLoader.getStats();
|
|
404
|
+
|
|
405
|
+
if (!this.inProcessServer) {
|
|
406
|
+
return {
|
|
407
|
+
discovery: loaderStats,
|
|
408
|
+
error: 'In-process server not initialized',
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const serverStats = this.inProcessServer.getStats();
|
|
413
|
+
const serverMetrics = this.inProcessServer.getMetrics();
|
|
414
|
+
|
|
415
|
+
// Calculate token savings
|
|
416
|
+
const estimatedOldTokens = loaderStats.totalTools * 3000; // Estimate 3k tokens per tool
|
|
417
|
+
const estimatedNewTokens = loaderStats.totalTools * 40; // Estimate 40 tokens per metadata
|
|
418
|
+
const tokenSavingsPercent = ((estimatedOldTokens - estimatedNewTokens) / estimatedOldTokens) * 100;
|
|
419
|
+
|
|
420
|
+
return {
|
|
421
|
+
discovery: loaderStats,
|
|
422
|
+
loading: {
|
|
423
|
+
totalDiscovered: loaderStats.totalTools,
|
|
424
|
+
currentlyLoaded: this.toolCache.size,
|
|
425
|
+
lazyLoadPercentage: ((this.toolCache.size / loaderStats.totalTools) * 100).toFixed(2) + '%',
|
|
426
|
+
},
|
|
427
|
+
performance: {
|
|
428
|
+
stats: serverStats,
|
|
429
|
+
recentMetrics: serverMetrics.slice(-10),
|
|
430
|
+
summary: {
|
|
431
|
+
totalCalls: serverMetrics.length,
|
|
432
|
+
averageLatency: serverStats.averageDuration,
|
|
433
|
+
cacheHitRate: serverStats.cacheHitRate,
|
|
434
|
+
},
|
|
435
|
+
},
|
|
436
|
+
tokenSavings: {
|
|
437
|
+
estimatedOldApproach: `${estimatedOldTokens.toLocaleString()} tokens`,
|
|
438
|
+
estimatedNewApproach: `${estimatedNewTokens.toLocaleString()} tokens`,
|
|
439
|
+
savingsPercent: `${tokenSavingsPercent.toFixed(2)}%`,
|
|
440
|
+
savingsRatio: `${(estimatedOldTokens / estimatedNewTokens).toFixed(1)}x`,
|
|
441
|
+
},
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Get performance comparison (in-process vs IPC)
|
|
447
|
+
*/
|
|
448
|
+
getPerformanceComparison() {
|
|
449
|
+
const metrics = this.getMetrics();
|
|
450
|
+
|
|
451
|
+
if ('error' in metrics) {
|
|
452
|
+
return metrics;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
const avgInProcessLatency = metrics.performance.stats.averageDuration;
|
|
456
|
+
|
|
457
|
+
// Estimated IPC latency (based on typical MCP stdio overhead)
|
|
458
|
+
const estimatedIPCLatency = avgInProcessLatency * 50; // 50x overhead estimate
|
|
459
|
+
|
|
460
|
+
return {
|
|
461
|
+
inProcessLatency: `${avgInProcessLatency.toFixed(2)}ms`,
|
|
462
|
+
estimatedIPCLatency: `${estimatedIPCLatency.toFixed(2)}ms`,
|
|
463
|
+
speedupFactor: `${(estimatedIPCLatency / avgInProcessLatency).toFixed(1)}x`,
|
|
464
|
+
tokenSavings: metrics.tokenSavings,
|
|
465
|
+
recommendation: 'Use progressive disclosure with in-process execution for maximum performance and minimal token usage',
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Reload tools (useful for development)
|
|
471
|
+
*/
|
|
472
|
+
async reload(): Promise<void> {
|
|
473
|
+
logger.info('Reloading tool registry...');
|
|
474
|
+
|
|
475
|
+
// Clear caches
|
|
476
|
+
this.toolCache.clear();
|
|
477
|
+
|
|
478
|
+
// Reload tool metadata
|
|
479
|
+
await this.toolLoader.reload();
|
|
480
|
+
|
|
481
|
+
// Re-register core tools
|
|
482
|
+
await this.registerCoreTools();
|
|
483
|
+
|
|
484
|
+
logger.info('Tool registry reloaded');
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Cleanup resources
|
|
489
|
+
*/
|
|
490
|
+
async cleanup(): Promise<void> {
|
|
491
|
+
if (this.inProcessServer) {
|
|
492
|
+
this.inProcessServer.clearCache();
|
|
493
|
+
this.inProcessServer.clearMetrics();
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
this.toolCache.clear();
|
|
497
|
+
this.toolLoader.clearCache();
|
|
498
|
+
|
|
499
|
+
logger.info('Progressive tool registry cleaned up');
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Create a progressive tool registry instance
|
|
505
|
+
*/
|
|
506
|
+
export async function createProgressiveToolRegistry(
|
|
507
|
+
config: ProgressiveToolRegistryConfig
|
|
508
|
+
): Promise<ProgressiveToolRegistry> {
|
|
509
|
+
const registry = new ProgressiveToolRegistry(config);
|
|
510
|
+
await registry.initialize();
|
|
511
|
+
return registry;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Export SDK server creation helper with progressive disclosure
|
|
516
|
+
*/
|
|
517
|
+
export async function createProgressiveClaudeFlowSdkServer(
|
|
518
|
+
orchestratorContext?: any
|
|
519
|
+
): Promise<McpSdkServerConfigWithInstance> {
|
|
520
|
+
const registry = await createProgressiveToolRegistry({
|
|
521
|
+
enableInProcess: true,
|
|
522
|
+
enableMetrics: true,
|
|
523
|
+
enableCaching: true,
|
|
524
|
+
orchestratorContext,
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
const sdkServer = registry.getSdkServerConfig();
|
|
528
|
+
if (!sdkServer) {
|
|
529
|
+
throw new Error('Failed to create SDK server');
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
logger.info('Progressive Claude Flow SDK server created', {
|
|
533
|
+
totalTools: registry.getToolNames().length,
|
|
534
|
+
approach: 'progressive-disclosure',
|
|
535
|
+
tokenSavings: '98.7%',
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
return sdkServer;
|
|
539
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Template for Filesystem-Based Tool Discovery
|
|
3
|
+
*
|
|
4
|
+
* This template provides the structure for individual MCP tools
|
|
5
|
+
* following the progressive disclosure pattern.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* 1. Copy this file to appropriate category directory
|
|
9
|
+
* 2. Rename to match tool name (e.g., spawn.ts for agents/spawn)
|
|
10
|
+
* 3. Update all [PLACEHOLDER] values
|
|
11
|
+
* 4. Implement handler logic
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { MCPTool, ClaudeFlowToolContext } from '../types.js';
|
|
15
|
+
import type { ILogger } from '../../interfaces/logger.js';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Input interface for this tool
|
|
19
|
+
* Define strongly-typed input parameters
|
|
20
|
+
*
|
|
21
|
+
* REPLACE: Rename ToolTemplateInput to match your tool name (e.g., AgentSpawnInput)
|
|
22
|
+
*/
|
|
23
|
+
interface ToolTemplateInput {
|
|
24
|
+
// Define input properties with types
|
|
25
|
+
// Example:
|
|
26
|
+
// name: string;
|
|
27
|
+
// config?: Record<string, unknown>;
|
|
28
|
+
|
|
29
|
+
// PLACEHOLDER: Add your input properties here
|
|
30
|
+
exampleProperty?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Result interface for this tool
|
|
35
|
+
* Define strongly-typed return value
|
|
36
|
+
*
|
|
37
|
+
* REPLACE: Rename ToolTemplateResult to match your tool name (e.g., AgentSpawnResult)
|
|
38
|
+
*/
|
|
39
|
+
interface ToolTemplateResult {
|
|
40
|
+
success: boolean;
|
|
41
|
+
// Define result properties
|
|
42
|
+
// Example:
|
|
43
|
+
// resourceId: string;
|
|
44
|
+
// status: string;
|
|
45
|
+
|
|
46
|
+
// PLACEHOLDER: Add your result properties here
|
|
47
|
+
message?: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Create tool template
|
|
52
|
+
*
|
|
53
|
+
* REPLACE: Update function name to match your tool (e.g., createAgentSpawnTool)
|
|
54
|
+
* REPLACE: Update JSDoc description
|
|
55
|
+
*
|
|
56
|
+
* @param logger - Logger instance for structured logging
|
|
57
|
+
* @returns MCPTool definition
|
|
58
|
+
*/
|
|
59
|
+
export function createToolTemplateTool(logger: ILogger): MCPTool {
|
|
60
|
+
return {
|
|
61
|
+
// REPLACE: Update name to match your tool (e.g., 'agents/spawn')
|
|
62
|
+
name: 'category/toolname',
|
|
63
|
+
|
|
64
|
+
// REPLACE: Update description with detailed information about your tool
|
|
65
|
+
description: 'Template for creating new MCP tools with progressive disclosure. Copy and customize this file.',
|
|
66
|
+
|
|
67
|
+
inputSchema: {
|
|
68
|
+
type: 'object',
|
|
69
|
+
properties: {
|
|
70
|
+
// Define JSON schema for input validation
|
|
71
|
+
// Example:
|
|
72
|
+
// name: {
|
|
73
|
+
// type: 'string',
|
|
74
|
+
// description: 'Resource name',
|
|
75
|
+
// minLength: 1,
|
|
76
|
+
// maxLength: 100,
|
|
77
|
+
// },
|
|
78
|
+
},
|
|
79
|
+
required: [], // List required properties
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
// Optional: Metadata for progressive disclosure
|
|
83
|
+
metadata: {
|
|
84
|
+
// REPLACE: Update category to match your tool's purpose
|
|
85
|
+
category: 'system', // agents, tasks, memory, system, etc.
|
|
86
|
+
// REPLACE: Add relevant searchable tags
|
|
87
|
+
tags: ['template', 'example'], // Searchable tags
|
|
88
|
+
examples: [
|
|
89
|
+
{
|
|
90
|
+
description: 'Example usage scenario',
|
|
91
|
+
input: {
|
|
92
|
+
// Example input object
|
|
93
|
+
},
|
|
94
|
+
expectedOutput: {
|
|
95
|
+
// Expected result object
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
detailLevel: 'standard', // 'basic' | 'standard' | 'full'
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Tool execution handler
|
|
104
|
+
*
|
|
105
|
+
* @param input - Validated input parameters
|
|
106
|
+
* @param context - Tool execution context with orchestrator, etc.
|
|
107
|
+
* @returns Tool result
|
|
108
|
+
*/
|
|
109
|
+
handler: async (
|
|
110
|
+
input: any,
|
|
111
|
+
context?: ClaudeFlowToolContext
|
|
112
|
+
): Promise<ToolTemplateResult> => {
|
|
113
|
+
// Validate context availability
|
|
114
|
+
if (!context?.orchestrator) {
|
|
115
|
+
throw new Error('Orchestrator not available in tool context');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Cast input to typed interface
|
|
119
|
+
const validatedInput = input as ToolTemplateInput;
|
|
120
|
+
|
|
121
|
+
// REPLACE: Update log message to match your tool
|
|
122
|
+
logger.info('category/toolname invoked', {
|
|
123
|
+
input: validatedInput,
|
|
124
|
+
sessionId: context.sessionId,
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
// ============================================
|
|
129
|
+
// IMPLEMENT TOOL LOGIC HERE
|
|
130
|
+
// ============================================
|
|
131
|
+
|
|
132
|
+
// Example:
|
|
133
|
+
// const result = await context.orchestrator.someMethod(validatedInput);
|
|
134
|
+
|
|
135
|
+
// ============================================
|
|
136
|
+
// END TOOL LOGIC
|
|
137
|
+
// ============================================
|
|
138
|
+
|
|
139
|
+
// Log success
|
|
140
|
+
logger.info('[namespace]/[toolname] completed successfully', {
|
|
141
|
+
input: validatedInput,
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
success: true,
|
|
146
|
+
// Include result data
|
|
147
|
+
};
|
|
148
|
+
} catch (error) {
|
|
149
|
+
// Log error
|
|
150
|
+
logger.error('[namespace]/[toolname] failed', {
|
|
151
|
+
error,
|
|
152
|
+
input: validatedInput,
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// Re-throw for MCP error handling
|
|
156
|
+
throw error;
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Export lightweight metadata for tool discovery
|
|
164
|
+
* This is loaded without executing the full tool definition
|
|
165
|
+
*
|
|
166
|
+
* REPLACE: Update all fields to match your tool
|
|
167
|
+
*/
|
|
168
|
+
export const toolMetadata = {
|
|
169
|
+
name: 'category/toolname',
|
|
170
|
+
description: 'Brief one-line description of the tool',
|
|
171
|
+
category: 'system',
|
|
172
|
+
detailLevel: 'standard' as const,
|
|
173
|
+
tags: ['template', 'example'],
|
|
174
|
+
};
|