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,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* System Status Tool
|
|
3
|
+
*
|
|
4
|
+
* Returns comprehensive system status including:
|
|
5
|
+
* - Uptime and version information
|
|
6
|
+
* - Active agents and tasks
|
|
7
|
+
* - Memory usage
|
|
8
|
+
* - Performance metrics
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { MCPTool, ClaudeFlowToolContext } from '../../types.js';
|
|
12
|
+
import type { ILogger } from '../../../interfaces/logger.js';
|
|
13
|
+
|
|
14
|
+
interface SystemStatusInput {
|
|
15
|
+
includeMetrics?: boolean;
|
|
16
|
+
includeAgents?: boolean;
|
|
17
|
+
includeTasks?: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface SystemStatusResult {
|
|
21
|
+
success: boolean;
|
|
22
|
+
status: 'healthy' | 'degraded' | 'unhealthy';
|
|
23
|
+
uptime: number;
|
|
24
|
+
version: string;
|
|
25
|
+
timestamp: string;
|
|
26
|
+
agents?: {
|
|
27
|
+
total: number;
|
|
28
|
+
active: number;
|
|
29
|
+
idle: number;
|
|
30
|
+
};
|
|
31
|
+
tasks?: {
|
|
32
|
+
total: number;
|
|
33
|
+
running: number;
|
|
34
|
+
completed: number;
|
|
35
|
+
failed: number;
|
|
36
|
+
};
|
|
37
|
+
metrics?: {
|
|
38
|
+
memoryUsage: number;
|
|
39
|
+
cpuUsage: number;
|
|
40
|
+
avgResponseTime: number;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function createSystemStatusTool(logger: ILogger): MCPTool {
|
|
45
|
+
return {
|
|
46
|
+
name: 'system/status',
|
|
47
|
+
description: 'Get comprehensive system status including uptime, active agents, tasks, and performance metrics. Use this to check system health.',
|
|
48
|
+
|
|
49
|
+
inputSchema: {
|
|
50
|
+
type: 'object',
|
|
51
|
+
properties: {
|
|
52
|
+
includeMetrics: {
|
|
53
|
+
type: 'boolean',
|
|
54
|
+
description: 'Include performance metrics',
|
|
55
|
+
default: false,
|
|
56
|
+
},
|
|
57
|
+
includeAgents: {
|
|
58
|
+
type: 'boolean',
|
|
59
|
+
description: 'Include agent statistics',
|
|
60
|
+
default: true,
|
|
61
|
+
},
|
|
62
|
+
includeTasks: {
|
|
63
|
+
type: 'boolean',
|
|
64
|
+
description: 'Include task statistics',
|
|
65
|
+
default: true,
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
required: [],
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
metadata: {
|
|
72
|
+
category: 'system',
|
|
73
|
+
tags: ['status', 'health', 'monitoring', 'metrics'],
|
|
74
|
+
examples: [
|
|
75
|
+
{
|
|
76
|
+
description: 'Get basic system status',
|
|
77
|
+
input: {},
|
|
78
|
+
expectedOutput: {
|
|
79
|
+
success: true,
|
|
80
|
+
status: 'healthy',
|
|
81
|
+
uptime: 3600000,
|
|
82
|
+
version: '2.7.32',
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
description: 'Get full system status with metrics',
|
|
87
|
+
input: {
|
|
88
|
+
includeMetrics: true,
|
|
89
|
+
includeAgents: true,
|
|
90
|
+
includeTasks: true,
|
|
91
|
+
},
|
|
92
|
+
expectedOutput: {
|
|
93
|
+
success: true,
|
|
94
|
+
status: 'healthy',
|
|
95
|
+
agents: { total: 5, active: 3, idle: 2 },
|
|
96
|
+
tasks: { total: 20, running: 5, completed: 12, failed: 3 },
|
|
97
|
+
metrics: { memoryUsage: 250, cpuUsage: 45, avgResponseTime: 150 },
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
detailLevel: 'standard',
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
handler: async (
|
|
105
|
+
input: any,
|
|
106
|
+
context?: ClaudeFlowToolContext
|
|
107
|
+
): Promise<SystemStatusResult> => {
|
|
108
|
+
if (!context?.orchestrator) {
|
|
109
|
+
throw new Error('Orchestrator not available in tool context');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const validatedInput = input as SystemStatusInput;
|
|
113
|
+
|
|
114
|
+
logger.info('system/status invoked', {
|
|
115
|
+
input: validatedInput,
|
|
116
|
+
sessionId: context.sessionId,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
// Get base status
|
|
121
|
+
const result: SystemStatusResult = {
|
|
122
|
+
success: true,
|
|
123
|
+
status: 'healthy',
|
|
124
|
+
uptime: process.uptime() * 1000, // Convert to milliseconds
|
|
125
|
+
version: process.env.npm_package_version || '2.7.32',
|
|
126
|
+
timestamp: new Date().toISOString(),
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// Get agent statistics if requested
|
|
130
|
+
if (validatedInput.includeAgents !== false) {
|
|
131
|
+
try {
|
|
132
|
+
const agentStats = await context.orchestrator.getAgentStats?.();
|
|
133
|
+
if (agentStats) {
|
|
134
|
+
result.agents = {
|
|
135
|
+
total: agentStats.total || 0,
|
|
136
|
+
active: agentStats.active || 0,
|
|
137
|
+
idle: agentStats.idle || 0,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
} catch (error) {
|
|
141
|
+
logger.warn('Failed to get agent statistics', { error });
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Get task statistics if requested
|
|
146
|
+
if (validatedInput.includeTasks !== false) {
|
|
147
|
+
try {
|
|
148
|
+
const taskStats = await context.orchestrator.getTaskStats?.();
|
|
149
|
+
if (taskStats) {
|
|
150
|
+
result.tasks = {
|
|
151
|
+
total: taskStats.total || 0,
|
|
152
|
+
running: taskStats.running || 0,
|
|
153
|
+
completed: taskStats.completed || 0,
|
|
154
|
+
failed: taskStats.failed || 0,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
} catch (error) {
|
|
158
|
+
logger.warn('Failed to get task statistics', { error });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Get performance metrics if requested
|
|
163
|
+
if (validatedInput.includeMetrics) {
|
|
164
|
+
try {
|
|
165
|
+
const memUsage = process.memoryUsage();
|
|
166
|
+
result.metrics = {
|
|
167
|
+
memoryUsage: Math.round(memUsage.heapUsed / 1024 / 1024), // MB
|
|
168
|
+
cpuUsage: Math.round(process.cpuUsage().user / 1000), // Approximate %
|
|
169
|
+
avgResponseTime: 0, // TODO: Get from metrics store
|
|
170
|
+
};
|
|
171
|
+
} catch (error) {
|
|
172
|
+
logger.warn('Failed to get performance metrics', { error });
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Determine overall health status
|
|
177
|
+
if (result.agents && result.agents.active === 0 && result.agents.total > 0) {
|
|
178
|
+
result.status = 'degraded';
|
|
179
|
+
}
|
|
180
|
+
if (result.tasks && result.tasks.failed > result.tasks.completed / 2) {
|
|
181
|
+
result.status = 'unhealthy';
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
logger.info('system/status completed successfully', {
|
|
185
|
+
status: result.status,
|
|
186
|
+
uptime: result.uptime,
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
return result;
|
|
190
|
+
} catch (error) {
|
|
191
|
+
logger.error('system/status failed', {
|
|
192
|
+
error,
|
|
193
|
+
input: validatedInput,
|
|
194
|
+
});
|
|
195
|
+
throw error;
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export const toolMetadata = {
|
|
202
|
+
name: 'system/status',
|
|
203
|
+
description: 'Get system health status and metrics',
|
|
204
|
+
category: 'system',
|
|
205
|
+
detailLevel: 'standard' as const,
|
|
206
|
+
};
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON Schema 1.1 Validator for MCP 2025-11
|
|
3
|
+
*
|
|
4
|
+
* Implements comprehensive schema validation per MCP 2025-11 specification
|
|
5
|
+
* using JSON Schema Draft 2020-12
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import Ajv, { type ErrorObject } from 'ajv';
|
|
9
|
+
import addFormats from 'ajv-formats';
|
|
10
|
+
import addErrors from 'ajv-errors';
|
|
11
|
+
import type { ILogger } from '../../interfaces/logger.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Validation result
|
|
15
|
+
*/
|
|
16
|
+
export interface ValidationResult {
|
|
17
|
+
valid: boolean;
|
|
18
|
+
errors?: Array<{
|
|
19
|
+
path: string;
|
|
20
|
+
message: string;
|
|
21
|
+
params?: any;
|
|
22
|
+
}>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Schema cache entry
|
|
27
|
+
*/
|
|
28
|
+
interface CachedSchema {
|
|
29
|
+
schema: object;
|
|
30
|
+
validate: any;
|
|
31
|
+
timestamp: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* MCP 2025-11 JSON Schema Validator
|
|
36
|
+
*
|
|
37
|
+
* Features:
|
|
38
|
+
* - JSON Schema Draft 2020-12 support
|
|
39
|
+
* - Format validation (uri, email, date-time, etc.)
|
|
40
|
+
* - Schema caching for performance
|
|
41
|
+
* - Custom error messages
|
|
42
|
+
* - $ref support
|
|
43
|
+
*/
|
|
44
|
+
export class SchemaValidator {
|
|
45
|
+
private ajv: Ajv;
|
|
46
|
+
private schemaCache: Map<string, CachedSchema> = new Map();
|
|
47
|
+
private cacheTTL = 3600000; // 1 hour
|
|
48
|
+
private readonly MAX_CACHE_SIZE = 1000; // Maximum cached schemas
|
|
49
|
+
|
|
50
|
+
constructor(private logger: ILogger) {
|
|
51
|
+
this.ajv = new Ajv({
|
|
52
|
+
allErrors: true,
|
|
53
|
+
strict: true,
|
|
54
|
+
validateFormats: true,
|
|
55
|
+
allowUnionTypes: true,
|
|
56
|
+
// Support JSON Schema Draft 2020-12
|
|
57
|
+
schemaId: 'auto',
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Add format validators (email, uri, date-time, etc.)
|
|
61
|
+
addFormats(this.ajv);
|
|
62
|
+
|
|
63
|
+
// Add custom error messages support
|
|
64
|
+
addErrors(this.ajv);
|
|
65
|
+
|
|
66
|
+
this.logger.info('Schema validator initialized', {
|
|
67
|
+
draft: '2020-12',
|
|
68
|
+
formats: 'enabled',
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Validate input against JSON Schema 1.1
|
|
74
|
+
*/
|
|
75
|
+
validateInput(schema: object, input: unknown): ValidationResult {
|
|
76
|
+
try {
|
|
77
|
+
const validate = this.getValidator(schema);
|
|
78
|
+
const valid = validate(input);
|
|
79
|
+
|
|
80
|
+
if (!valid && validate.errors) {
|
|
81
|
+
return {
|
|
82
|
+
valid: false,
|
|
83
|
+
errors: this.formatErrors(validate.errors),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return { valid: true };
|
|
88
|
+
} catch (error) {
|
|
89
|
+
this.logger.error('Schema validation error', {
|
|
90
|
+
error: error instanceof Error ? error.message : String(error),
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
valid: false,
|
|
95
|
+
errors: [{
|
|
96
|
+
path: '',
|
|
97
|
+
message: 'Schema validation failed',
|
|
98
|
+
}],
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Validate output against schema
|
|
105
|
+
*/
|
|
106
|
+
validateOutput(schema: object, output: unknown): ValidationResult {
|
|
107
|
+
return this.validateInput(schema, output);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Validate tool schema itself
|
|
112
|
+
*/
|
|
113
|
+
validateToolSchema(toolSchema: object): ValidationResult {
|
|
114
|
+
// Ensure schema has required fields
|
|
115
|
+
const requiredFields = ['$schema', 'type', 'properties'];
|
|
116
|
+
const schemaObj = toolSchema as any;
|
|
117
|
+
|
|
118
|
+
const missing = requiredFields.filter(field => !(field in schemaObj));
|
|
119
|
+
if (missing.length > 0) {
|
|
120
|
+
return {
|
|
121
|
+
valid: false,
|
|
122
|
+
errors: missing.map(field => ({
|
|
123
|
+
path: '/',
|
|
124
|
+
message: `Missing required field: ${field}`,
|
|
125
|
+
})),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Validate schema is valid JSON Schema
|
|
130
|
+
try {
|
|
131
|
+
this.ajv.compile(toolSchema);
|
|
132
|
+
return { valid: true };
|
|
133
|
+
} catch (error) {
|
|
134
|
+
return {
|
|
135
|
+
valid: false,
|
|
136
|
+
errors: [{
|
|
137
|
+
path: '/',
|
|
138
|
+
message: error instanceof Error ? error.message : 'Invalid schema',
|
|
139
|
+
}],
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Get or create validator for schema
|
|
146
|
+
*/
|
|
147
|
+
private getValidator(schema: object): any {
|
|
148
|
+
const schemaKey = JSON.stringify(schema);
|
|
149
|
+
const cached = this.schemaCache.get(schemaKey);
|
|
150
|
+
|
|
151
|
+
// Return cached validator if still valid
|
|
152
|
+
if (cached && Date.now() - cached.timestamp < this.cacheTTL) {
|
|
153
|
+
return cached.validate;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Compile new validator
|
|
157
|
+
try {
|
|
158
|
+
const validate = this.ajv.compile(schema);
|
|
159
|
+
|
|
160
|
+
// Enforce cache size limit (LRU eviction - remove oldest entry)
|
|
161
|
+
if (this.schemaCache.size >= this.MAX_CACHE_SIZE) {
|
|
162
|
+
const oldest = Array.from(this.schemaCache.entries())
|
|
163
|
+
.sort((a, b) => a[1].timestamp - b[1].timestamp)[0];
|
|
164
|
+
|
|
165
|
+
if (oldest) {
|
|
166
|
+
this.schemaCache.delete(oldest[0]);
|
|
167
|
+
this.logger.debug('Evicted oldest schema from cache', {
|
|
168
|
+
cacheSize: this.schemaCache.size,
|
|
169
|
+
maxSize: this.MAX_CACHE_SIZE,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Cache for future use
|
|
175
|
+
this.schemaCache.set(schemaKey, {
|
|
176
|
+
schema,
|
|
177
|
+
validate,
|
|
178
|
+
timestamp: Date.now(),
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
return validate;
|
|
182
|
+
} catch (error) {
|
|
183
|
+
this.logger.error('Failed to compile schema', {
|
|
184
|
+
error: error instanceof Error ? error.message : String(error),
|
|
185
|
+
});
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Format ajv errors to user-friendly format
|
|
192
|
+
*/
|
|
193
|
+
private formatErrors(errors: ErrorObject[]): ValidationResult['errors'] {
|
|
194
|
+
return errors.map(err => ({
|
|
195
|
+
path: err.instancePath || '/',
|
|
196
|
+
message: this.getErrorMessage(err),
|
|
197
|
+
params: err.params,
|
|
198
|
+
}));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Get user-friendly error message
|
|
203
|
+
*/
|
|
204
|
+
private getErrorMessage(error: ErrorObject): string {
|
|
205
|
+
const { keyword, message, params } = error;
|
|
206
|
+
|
|
207
|
+
switch (keyword) {
|
|
208
|
+
case 'required':
|
|
209
|
+
return `Missing required property: ${params.missingProperty}`;
|
|
210
|
+
case 'type':
|
|
211
|
+
return `Expected ${params.type} but got ${typeof params.data}`;
|
|
212
|
+
case 'format':
|
|
213
|
+
return `Invalid format for ${params.format}`;
|
|
214
|
+
case 'minimum':
|
|
215
|
+
return `Value must be >= ${params.limit}`;
|
|
216
|
+
case 'maximum':
|
|
217
|
+
return `Value must be <= ${params.limit}`;
|
|
218
|
+
case 'minLength':
|
|
219
|
+
return `String must be at least ${params.limit} characters`;
|
|
220
|
+
case 'maxLength':
|
|
221
|
+
return `String must be at most ${params.limit} characters`;
|
|
222
|
+
case 'pattern':
|
|
223
|
+
return `String must match pattern: ${params.pattern}`;
|
|
224
|
+
case 'enum':
|
|
225
|
+
return `Value must be one of: ${params.allowedValues?.join(', ')}`;
|
|
226
|
+
default:
|
|
227
|
+
return message || `Validation failed: ${keyword}`;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Clear schema cache
|
|
233
|
+
*/
|
|
234
|
+
clearCache(): void {
|
|
235
|
+
this.schemaCache.clear();
|
|
236
|
+
this.logger.info('Schema cache cleared');
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Get cache statistics
|
|
241
|
+
*/
|
|
242
|
+
getCacheStats() {
|
|
243
|
+
return {
|
|
244
|
+
size: this.schemaCache.size,
|
|
245
|
+
entries: Array.from(this.schemaCache.values()).map(entry => ({
|
|
246
|
+
age: Date.now() - entry.timestamp,
|
|
247
|
+
expired: Date.now() - entry.timestamp > this.cacheTTL,
|
|
248
|
+
})),
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Cleanup expired cache entries
|
|
254
|
+
*/
|
|
255
|
+
cleanupCache(): number {
|
|
256
|
+
const now = Date.now();
|
|
257
|
+
let cleaned = 0;
|
|
258
|
+
|
|
259
|
+
for (const [key, entry] of this.schemaCache.entries()) {
|
|
260
|
+
if (now - entry.timestamp > this.cacheTTL) {
|
|
261
|
+
this.schemaCache.delete(key);
|
|
262
|
+
cleaned++;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (cleaned > 0) {
|
|
267
|
+
this.logger.info('Cleaned up expired schema cache entries', { count: cleaned });
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return cleaned;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Convert legacy tool schema to MCP 2025-11 format
|
|
276
|
+
*/
|
|
277
|
+
export function upgradeToolSchema(legacySchema: any): object {
|
|
278
|
+
// If already in 2025-11 format, return as-is
|
|
279
|
+
if (legacySchema.$schema && legacySchema.$schema.includes('2020-12')) {
|
|
280
|
+
return legacySchema;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Convert to 2025-11 format
|
|
284
|
+
return {
|
|
285
|
+
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
|
286
|
+
type: legacySchema.type || 'object',
|
|
287
|
+
properties: legacySchema.properties || {},
|
|
288
|
+
required: legacySchema.required || [],
|
|
289
|
+
additionalProperties: legacySchema.additionalProperties !== undefined
|
|
290
|
+
? legacySchema.additionalProperties
|
|
291
|
+
: false,
|
|
292
|
+
description: legacySchema.description,
|
|
293
|
+
};
|
|
294
|
+
}
|