@bryan-thompson/inspector-assessment 1.5.0 → 1.7.0

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.
Files changed (77) hide show
  1. package/cli/build/assess-full.js +528 -0
  2. package/cli/build/assess-security.js +342 -0
  3. package/cli/build/cli.js +10 -1
  4. package/client/dist/assets/{OAuthCallback-TeTvKfWE.js → OAuthCallback-Xo9zS7pv.js} +1 -1
  5. package/client/dist/assets/{OAuthDebugCallback-DwA2sKy9.js → OAuthDebugCallback-CaIey8K_.js} +1 -1
  6. package/client/dist/assets/{index-BwAoxcvr.js → index-nCPw6E-c.js} +4 -4
  7. package/client/dist/index.html +1 -1
  8. package/client/lib/lib/assessmentTypes.d.ts +670 -0
  9. package/client/lib/lib/assessmentTypes.d.ts.map +1 -0
  10. package/client/lib/lib/assessmentTypes.js +220 -0
  11. package/client/lib/lib/aupPatterns.d.ts +63 -0
  12. package/client/lib/lib/aupPatterns.d.ts.map +1 -0
  13. package/client/lib/lib/aupPatterns.js +344 -0
  14. package/client/lib/lib/prohibitedLibraries.d.ts +76 -0
  15. package/client/lib/lib/prohibitedLibraries.d.ts.map +1 -0
  16. package/client/lib/lib/prohibitedLibraries.js +364 -0
  17. package/client/lib/lib/securityPatterns.d.ts +64 -0
  18. package/client/lib/lib/securityPatterns.d.ts.map +1 -0
  19. package/client/lib/lib/securityPatterns.js +453 -0
  20. package/client/lib/services/assessment/AssessmentOrchestrator.d.ts +88 -0
  21. package/client/lib/services/assessment/AssessmentOrchestrator.d.ts.map +1 -0
  22. package/client/lib/services/assessment/AssessmentOrchestrator.js +418 -0
  23. package/client/lib/services/assessment/ResponseValidator.d.ts +69 -0
  24. package/client/lib/services/assessment/ResponseValidator.d.ts.map +1 -0
  25. package/client/lib/services/assessment/ResponseValidator.js +1038 -0
  26. package/client/lib/services/assessment/TestDataGenerator.d.ts +86 -0
  27. package/client/lib/services/assessment/TestDataGenerator.d.ts.map +1 -0
  28. package/client/lib/services/assessment/TestDataGenerator.js +669 -0
  29. package/client/lib/services/assessment/TestScenarioEngine.d.ts +91 -0
  30. package/client/lib/services/assessment/TestScenarioEngine.d.ts.map +1 -0
  31. package/client/lib/services/assessment/TestScenarioEngine.js +505 -0
  32. package/client/lib/services/assessment/ToolClassifier.d.ts +61 -0
  33. package/client/lib/services/assessment/ToolClassifier.d.ts.map +1 -0
  34. package/client/lib/services/assessment/ToolClassifier.js +349 -0
  35. package/client/lib/services/assessment/lib/claudeCodeBridge.d.ts +160 -0
  36. package/client/lib/services/assessment/lib/claudeCodeBridge.d.ts.map +1 -0
  37. package/client/lib/services/assessment/lib/claudeCodeBridge.js +357 -0
  38. package/client/lib/services/assessment/modules/AUPComplianceAssessor.d.ts +100 -0
  39. package/client/lib/services/assessment/modules/AUPComplianceAssessor.d.ts.map +1 -0
  40. package/client/lib/services/assessment/modules/AUPComplianceAssessor.js +474 -0
  41. package/client/lib/services/assessment/modules/BaseAssessor.d.ts +71 -0
  42. package/client/lib/services/assessment/modules/BaseAssessor.d.ts.map +1 -0
  43. package/client/lib/services/assessment/modules/BaseAssessor.js +171 -0
  44. package/client/lib/services/assessment/modules/DocumentationAssessor.d.ts +45 -0
  45. package/client/lib/services/assessment/modules/DocumentationAssessor.d.ts.map +1 -0
  46. package/client/lib/services/assessment/modules/DocumentationAssessor.js +355 -0
  47. package/client/lib/services/assessment/modules/ErrorHandlingAssessor.d.ts +25 -0
  48. package/client/lib/services/assessment/modules/ErrorHandlingAssessor.d.ts.map +1 -0
  49. package/client/lib/services/assessment/modules/ErrorHandlingAssessor.js +564 -0
  50. package/client/lib/services/assessment/modules/FunctionalityAssessor.d.ts +20 -0
  51. package/client/lib/services/assessment/modules/FunctionalityAssessor.d.ts.map +1 -0
  52. package/client/lib/services/assessment/modules/FunctionalityAssessor.js +253 -0
  53. package/client/lib/services/assessment/modules/MCPSpecComplianceAssessor.d.ts +70 -0
  54. package/client/lib/services/assessment/modules/MCPSpecComplianceAssessor.d.ts.map +1 -0
  55. package/client/lib/services/assessment/modules/MCPSpecComplianceAssessor.js +508 -0
  56. package/client/lib/services/assessment/modules/ManifestValidationAssessor.d.ts +70 -0
  57. package/client/lib/services/assessment/modules/ManifestValidationAssessor.d.ts.map +1 -0
  58. package/client/lib/services/assessment/modules/ManifestValidationAssessor.js +430 -0
  59. package/client/lib/services/assessment/modules/PortabilityAssessor.d.ts +43 -0
  60. package/client/lib/services/assessment/modules/PortabilityAssessor.d.ts.map +1 -0
  61. package/client/lib/services/assessment/modules/PortabilityAssessor.js +347 -0
  62. package/client/lib/services/assessment/modules/ProhibitedLibrariesAssessor.d.ts +41 -0
  63. package/client/lib/services/assessment/modules/ProhibitedLibrariesAssessor.d.ts.map +1 -0
  64. package/client/lib/services/assessment/modules/ProhibitedLibrariesAssessor.js +256 -0
  65. package/client/lib/services/assessment/modules/SecurityAssessor.d.ts +176 -0
  66. package/client/lib/services/assessment/modules/SecurityAssessor.d.ts.map +1 -0
  67. package/client/lib/services/assessment/modules/SecurityAssessor.js +1333 -0
  68. package/client/lib/services/assessment/modules/ToolAnnotationAssessor.d.ts +96 -0
  69. package/client/lib/services/assessment/modules/ToolAnnotationAssessor.d.ts.map +1 -0
  70. package/client/lib/services/assessment/modules/ToolAnnotationAssessor.js +593 -0
  71. package/client/lib/services/assessment/modules/UsabilityAssessor.d.ts +21 -0
  72. package/client/lib/services/assessment/modules/UsabilityAssessor.d.ts.map +1 -0
  73. package/client/lib/services/assessment/modules/UsabilityAssessor.js +241 -0
  74. package/client/lib/services/assessment/modules/index.d.ts +33 -0
  75. package/client/lib/services/assessment/modules/index.d.ts.map +1 -0
  76. package/client/lib/services/assessment/modules/index.js +35 -0
  77. package/package.json +7 -2
@@ -0,0 +1,669 @@
1
+ /**
2
+ * Smart Test Data Generator for MCP Tool Testing
3
+ * Generates realistic, context-aware test data based on parameter schemas
4
+ *
5
+ * Supports optional Claude Code integration for intelligent test generation
6
+ * when ClaudeCodeBridge is provided.
7
+ */
8
+ export class TestDataGenerator {
9
+ // Optional Claude Code bridge for intelligent test generation
10
+ static claudeBridge = null;
11
+ /**
12
+ * Set the Claude Code bridge for intelligent test generation
13
+ * Call this once during initialization if Claude integration is enabled
14
+ */
15
+ static setClaudeBridge(bridge) {
16
+ this.claudeBridge = bridge;
17
+ }
18
+ /**
19
+ * Check if Claude Code integration is available and enabled
20
+ */
21
+ static isClaudeEnabled() {
22
+ return (this.claudeBridge !== null &&
23
+ this.claudeBridge.isFeatureEnabled("intelligentTestGeneration"));
24
+ }
25
+ // Realistic data pools for different types - using values that are more likely to exist
26
+ static REALISTIC_DATA = {
27
+ urls: [
28
+ "https://www.google.com", // Public, always accessible
29
+ "https://api.github.com/users/octocat", // Public API endpoint that exists
30
+ "https://jsonplaceholder.typicode.com/posts/1", // Test API that always works
31
+ "https://httpbin.org/get", // HTTP testing service
32
+ "https://example.com", // RFC 2606 reserved domain for examples
33
+ "https://www.wikipedia.org", // Public, stable site
34
+ "https://api.openweathermap.org/data/2.5/weather?q=London", // Public API
35
+ ],
36
+ emails: [
37
+ "admin@example.com", // Common admin email
38
+ "support@example.com", // Common support email
39
+ "info@example.com", // Common info email
40
+ "test@test.com", // Generic test email
41
+ "user@domain.com", // Generic user email
42
+ "noreply@example.com", // Common no-reply format
43
+ "hello@world.com", // Simple, memorable
44
+ ],
45
+ names: [
46
+ "Default", // Common default name
47
+ "Admin", // Common admin user
48
+ "Test User", // Clear test user
49
+ "Sample Item", // Generic sample
50
+ "Example Project", // Clear example
51
+ "Demo Application", // Common demo name
52
+ "Main", // Common main/primary name
53
+ ],
54
+ ids: [
55
+ "1", // Simple numeric ID that often exists
56
+ "123", // Common test ID
57
+ "550e8400-e29b-41d4-a716-446655440000", // Valid UUID v4 (replaces "test")
58
+ "default", // Common default ID
59
+ "main", // Common main ID
60
+ "264051cd-48ab-80ff-864e-d1aa9bc41429", // Valid UUID from realistic data
61
+ "00000000-0000-0000-0000-000000000000", // Nil UUID (often used as placeholder)
62
+ "admin", // Common admin ID
63
+ "user1", // Common user ID pattern
64
+ ],
65
+ paths: [
66
+ "/tmp/test.txt", // Common temp file path (usually writable)
67
+ "/home", // Common home directory
68
+ "./README.md", // Often exists in projects
69
+ "./package.json", // Common in Node projects
70
+ "./src", // Common source directory
71
+ "./test", // Common test directory
72
+ "./config", // Common config directory
73
+ "/var/log", // Common log directory (readable)
74
+ "/etc", // Common config directory (readable)
75
+ ],
76
+ queries: [
77
+ "test", // Simple search term
78
+ "hello", // Common greeting
79
+ "*", // Wildcard that matches everything
80
+ "name", // Common field name
81
+ "id:1", // Common ID search
82
+ "status:active", // Common status filter
83
+ "type:user", // Common type filter
84
+ "limit:10", // Common pagination
85
+ '{"match_all": {}}', // Elasticsearch match all
86
+ ],
87
+ numbers: [0, 1, 10, 100, 1000, 5, 50, 200, 404, 500],
88
+ booleans: [true, false],
89
+ jsonObjects: [
90
+ { message: "Hello World" }, // Simple message object
91
+ { status: "ok", code: 200 }, // Common status response
92
+ { data: [], total: 0 }, // Empty result set
93
+ { id: 1, name: "Test" }, // Simple entity
94
+ { success: true }, // Common success response
95
+ { error: false }, // Common no-error response
96
+ { results: [] }, // Common empty results
97
+ {}, // Empty object (often valid)
98
+ ],
99
+ arrays: [
100
+ [], // Empty array (often valid)
101
+ [1], // Single item
102
+ ["a", "b", "c"], // Simple string array
103
+ [1, 2, 3], // Simple number array
104
+ [{ id: 1 }, { id: 2 }], // Simple object array
105
+ ["test"], // Single test item
106
+ [true, false], // Boolean array
107
+ ],
108
+ timestamps: [
109
+ new Date().toISOString(), // Current time (always valid)
110
+ new Date(Date.now() - 86400000).toISOString(), // Yesterday
111
+ new Date(Date.now() + 86400000).toISOString(), // Tomorrow
112
+ "2024-01-01T00:00:00Z", // New Year 2024
113
+ "2023-12-31T23:59:59Z", // End of 2023
114
+ new Date(0).toISOString(), // Unix epoch
115
+ "2024-06-15T12:00:00Z", // Midday mid-year
116
+ ],
117
+ };
118
+ /**
119
+ * Generate multiple test scenarios for a tool
120
+ * Uses Claude Code if available for intelligent generation,
121
+ * otherwise falls back to schema-based generation.
122
+ */
123
+ static generateTestScenarios(tool) {
124
+ const scenarios = [];
125
+ // Always include at least one happy path scenario
126
+ scenarios.push(this.generateHappyPathScenario(tool));
127
+ // Add edge cases based on tool complexity
128
+ const edgeCases = this.generateEdgeCaseScenarios(tool);
129
+ scenarios.push(...edgeCases);
130
+ // Add boundary value scenarios for numeric inputs
131
+ const boundaryScenarios = this.generateBoundaryScenarios(tool);
132
+ scenarios.push(...boundaryScenarios);
133
+ // Add one error scenario to test error handling
134
+ scenarios.push(this.generateErrorScenario(tool));
135
+ return scenarios;
136
+ }
137
+ /**
138
+ * Generate test scenarios with optional Claude enhancement
139
+ * This async version tries Claude first if enabled, then falls back to schema-based.
140
+ */
141
+ static async generateTestScenariosAsync(tool) {
142
+ // Try Claude-enhanced generation first
143
+ if (this.isClaudeEnabled() && this.claudeBridge) {
144
+ try {
145
+ const claudeParams = await this.claudeBridge.generateTestParameters(tool);
146
+ if (claudeParams && claudeParams.length > 0) {
147
+ console.log(`[TestDataGenerator] Using Claude-generated params for ${tool.name}`);
148
+ // Convert Claude params to TestScenario format
149
+ const claudeScenarios = claudeParams.map((params, index) => ({
150
+ name: this.getClaudeScenarioName(index),
151
+ description: `Claude-generated test case ${index + 1} for ${tool.name}`,
152
+ params,
153
+ expectedBehavior: "Should execute successfully with valid response",
154
+ category: this.getClaudeScenarioCategory(index),
155
+ source: "claude-generated",
156
+ }));
157
+ // Add one error scenario (Claude focuses on valid inputs)
158
+ claudeScenarios.push({
159
+ ...this.generateErrorScenario(tool),
160
+ source: "schema-based",
161
+ });
162
+ return claudeScenarios;
163
+ }
164
+ }
165
+ catch (error) {
166
+ console.warn(`[TestDataGenerator] Claude generation failed for ${tool.name}, falling back to schema-based:`, error);
167
+ }
168
+ }
169
+ // Fall back to schema-based generation
170
+ return this.generateTestScenarios(tool).map((scenario) => ({
171
+ ...scenario,
172
+ source: "schema-based",
173
+ }));
174
+ }
175
+ /**
176
+ * Get scenario name based on index for Claude-generated scenarios
177
+ */
178
+ static getClaudeScenarioName(index) {
179
+ const names = [
180
+ "Happy Path - Typical Usage",
181
+ "Edge Case - Boundary Values",
182
+ "Minimal Input - Required Fields Only",
183
+ "Comprehensive - All Fields Populated",
184
+ "Variant - Alternative Valid Input",
185
+ ];
186
+ return names[index] || `Test Case ${index + 1}`;
187
+ }
188
+ /**
189
+ * Get scenario category based on index for Claude-generated scenarios
190
+ */
191
+ static getClaudeScenarioCategory(index) {
192
+ const categories = [
193
+ "happy_path",
194
+ "edge_case",
195
+ "boundary",
196
+ "happy_path",
197
+ "edge_case",
198
+ ];
199
+ return categories[index] || "happy_path";
200
+ }
201
+ /**
202
+ * Generate a happy path scenario with realistic data
203
+ */
204
+ static generateHappyPathScenario(tool) {
205
+ const params = this.generateRealisticParams(tool, "typical");
206
+ return {
207
+ name: "Happy Path - Typical Usage",
208
+ description: `Test ${tool.name} with typical, valid inputs`,
209
+ params,
210
+ expectedBehavior: "Should execute successfully and return valid response",
211
+ category: "happy_path",
212
+ };
213
+ }
214
+ /**
215
+ * Generate edge case scenarios
216
+ */
217
+ static generateEdgeCaseScenarios(tool) {
218
+ const scenarios = [];
219
+ // Empty values scenario (where applicable)
220
+ const emptyParams = this.generateRealisticParams(tool, "empty");
221
+ if (Object.keys(emptyParams).length > 0) {
222
+ scenarios.push({
223
+ name: "Edge Case - Empty Values",
224
+ description: "Test with empty but valid values",
225
+ params: emptyParams,
226
+ expectedBehavior: "Should handle empty values gracefully",
227
+ category: "edge_case",
228
+ });
229
+ }
230
+ // Maximum values scenario
231
+ const maxParams = this.generateRealisticParams(tool, "maximum");
232
+ scenarios.push({
233
+ name: "Edge Case - Maximum Values",
234
+ description: "Test with maximum/large values",
235
+ params: maxParams,
236
+ expectedBehavior: "Should handle large inputs without issues",
237
+ category: "edge_case",
238
+ });
239
+ // Special characters scenario (for string inputs)
240
+ if (this.hasStringInputs(tool)) {
241
+ const specialParams = this.generateRealisticParams(tool, "special");
242
+ scenarios.push({
243
+ name: "Edge Case - Special Characters",
244
+ description: "Test with special characters and unicode",
245
+ params: specialParams,
246
+ expectedBehavior: "Should properly handle special characters",
247
+ category: "edge_case",
248
+ });
249
+ }
250
+ return scenarios;
251
+ }
252
+ /**
253
+ * Generate boundary value scenarios
254
+ */
255
+ static generateBoundaryScenarios(tool) {
256
+ const scenarios = [];
257
+ if (!tool.inputSchema || tool.inputSchema.type !== "object") {
258
+ return scenarios;
259
+ }
260
+ const properties = tool.inputSchema.properties || {};
261
+ // OPTIMIZATION: Check if any fields have boundary constraints before generating tests
262
+ // This prevents running boundary tests on tools that don't define min/max constraints
263
+ let hasBoundaries = false;
264
+ for (const [_key, schema] of Object.entries(properties)) {
265
+ const schemaObj = schema;
266
+ if (schemaObj.minimum !== undefined ||
267
+ schemaObj.maximum !== undefined ||
268
+ schemaObj.minLength !== undefined ||
269
+ schemaObj.maxLength !== undefined) {
270
+ hasBoundaries = true;
271
+ break;
272
+ }
273
+ }
274
+ // Early return if no boundaries defined - saves 0-4 test scenarios per tool
275
+ if (!hasBoundaries) {
276
+ return scenarios;
277
+ }
278
+ for (const [key, schema] of Object.entries(properties)) {
279
+ const schemaObj = schema;
280
+ // Test numeric boundaries
281
+ if (schemaObj.type === "number" || schemaObj.type === "integer") {
282
+ if (schemaObj.minimum !== undefined) {
283
+ const params = this.generateRealisticParams(tool, "typical");
284
+ params[key] = schemaObj.minimum;
285
+ scenarios.push({
286
+ name: `Boundary - ${key} at minimum`,
287
+ description: `Test ${key} at its minimum value`,
288
+ params,
289
+ expectedBehavior: "Should accept minimum value",
290
+ category: "boundary",
291
+ });
292
+ }
293
+ if (schemaObj.maximum !== undefined) {
294
+ const params = this.generateRealisticParams(tool, "typical");
295
+ params[key] = schemaObj.maximum;
296
+ scenarios.push({
297
+ name: `Boundary - ${key} at maximum`,
298
+ description: `Test ${key} at its maximum value`,
299
+ params,
300
+ expectedBehavior: "Should accept maximum value",
301
+ category: "boundary",
302
+ });
303
+ }
304
+ }
305
+ // Test string length boundaries
306
+ if (schemaObj.type === "string") {
307
+ if (schemaObj.minLength !== undefined) {
308
+ const params = this.generateRealisticParams(tool, "typical");
309
+ params[key] = "a".repeat(schemaObj.minLength);
310
+ scenarios.push({
311
+ name: `Boundary - ${key} at min length`,
312
+ description: `Test ${key} at minimum length`,
313
+ params,
314
+ expectedBehavior: "Should accept minimum length string",
315
+ category: "boundary",
316
+ });
317
+ }
318
+ if (schemaObj.maxLength !== undefined) {
319
+ const params = this.generateRealisticParams(tool, "typical");
320
+ params[key] = "a".repeat(schemaObj.maxLength);
321
+ scenarios.push({
322
+ name: `Boundary - ${key} at max length`,
323
+ description: `Test ${key} at maximum length`,
324
+ params,
325
+ expectedBehavior: "Should accept maximum length string",
326
+ category: "boundary",
327
+ });
328
+ }
329
+ }
330
+ }
331
+ return scenarios;
332
+ }
333
+ /**
334
+ * Generate an error scenario
335
+ */
336
+ static generateErrorScenario(tool) {
337
+ const params = {};
338
+ if (tool.inputSchema &&
339
+ tool.inputSchema.type === "object" &&
340
+ tool.inputSchema.properties) {
341
+ // Intentionally provide wrong types
342
+ for (const [key, schema] of Object.entries(tool.inputSchema.properties)) {
343
+ const schemaObj = schema;
344
+ switch (schemaObj.type) {
345
+ case "string":
346
+ params[key] = 123; // Wrong type
347
+ break;
348
+ case "number":
349
+ case "integer":
350
+ params[key] = "not_a_number"; // Wrong type
351
+ break;
352
+ case "boolean":
353
+ params[key] = "not_a_boolean"; // Wrong type
354
+ break;
355
+ case "array":
356
+ params[key] = "not_an_array"; // Wrong type
357
+ break;
358
+ case "object":
359
+ params[key] = "not_an_object"; // Wrong type
360
+ break;
361
+ default:
362
+ params[key] = null;
363
+ }
364
+ // Only set one wrong parameter to make the error clear
365
+ break;
366
+ }
367
+ }
368
+ return {
369
+ name: "Error Case - Invalid Type",
370
+ description: "Test error handling with invalid parameter types",
371
+ params,
372
+ expectedBehavior: "Should return clear error about invalid parameter type",
373
+ category: "error_case",
374
+ };
375
+ }
376
+ /**
377
+ * Generate realistic parameters based on schema and variant
378
+ */
379
+ static generateRealisticParams(tool, variant) {
380
+ const params = {};
381
+ if (!tool.inputSchema || tool.inputSchema.type !== "object") {
382
+ return params;
383
+ }
384
+ const properties = tool.inputSchema.properties || {};
385
+ for (const [key, schema] of Object.entries(properties)) {
386
+ params[key] = this.generateRealisticValue(key, schema, variant);
387
+ }
388
+ return params;
389
+ }
390
+ /**
391
+ * Generate a realistic value based on field name and schema
392
+ */
393
+ static generateRealisticValue(fieldName, schema, variant) {
394
+ const lowerFieldName = fieldName.toLowerCase();
395
+ switch (schema.type) {
396
+ case "string":
397
+ // Check for enums first
398
+ if (schema.enum && schema.enum.length > 0) {
399
+ return variant === "typical"
400
+ ? schema.enum[0]
401
+ : schema.enum[schema.enum.length - 1];
402
+ }
403
+ // Context-aware string generation
404
+ if (lowerFieldName.includes("url") ||
405
+ lowerFieldName.includes("link") ||
406
+ lowerFieldName.includes("endpoint")) {
407
+ return variant === "empty"
408
+ ? ""
409
+ : variant === "maximum"
410
+ ? "https://very-long-domain-name-for-testing-maximum-length.example.com/path/to/resource?param1=value1&param2=value2"
411
+ : variant === "special"
412
+ ? "https://example.com/path?special=!@#$%^&*()"
413
+ : this.REALISTIC_DATA.urls[Math.floor(Math.random() * this.REALISTIC_DATA.urls.length)];
414
+ }
415
+ if (lowerFieldName.includes("email") ||
416
+ lowerFieldName.includes("mail")) {
417
+ return variant === "empty"
418
+ ? ""
419
+ : variant === "maximum"
420
+ ? "very.long.email.address.for.testing@subdomain.example-company.co.uk"
421
+ : variant === "special"
422
+ ? "user+tag@example.com"
423
+ : this.REALISTIC_DATA.emails[Math.floor(Math.random() * this.REALISTIC_DATA.emails.length)];
424
+ }
425
+ if (lowerFieldName.includes("path") ||
426
+ lowerFieldName.includes("file") ||
427
+ lowerFieldName.includes("directory") ||
428
+ lowerFieldName.includes("folder")) {
429
+ return variant === "empty"
430
+ ? ""
431
+ : variant === "maximum"
432
+ ? "/very/long/path/to/deeply/nested/directory/structure/for/testing/file.txt"
433
+ : variant === "special"
434
+ ? "./path/with spaces/and-special#chars.txt"
435
+ : this.REALISTIC_DATA.paths[Math.floor(Math.random() * this.REALISTIC_DATA.paths.length)];
436
+ }
437
+ if (lowerFieldName.includes("query") ||
438
+ lowerFieldName.includes("search") ||
439
+ lowerFieldName.includes("filter")) {
440
+ return variant === "empty"
441
+ ? "test" // Use "test" instead of "" to ensure search tools have valid input
442
+ : variant === "maximum"
443
+ ? "very long search query with many terms for testing maximum input length handling"
444
+ : variant === "special"
445
+ ? 'search with "quotes" and special: characters!'
446
+ : this.REALISTIC_DATA.queries[Math.floor(Math.random() * this.REALISTIC_DATA.queries.length)];
447
+ }
448
+ if (lowerFieldName.includes("id") ||
449
+ lowerFieldName.includes("key") ||
450
+ lowerFieldName.includes("identifier")) {
451
+ // Check if this field requires UUID format based on common patterns
452
+ const requiresUuid = lowerFieldName.includes("uuid") ||
453
+ lowerFieldName.includes("page_id") ||
454
+ lowerFieldName.includes("database_id") ||
455
+ lowerFieldName.includes("user_id") ||
456
+ lowerFieldName.includes("block_id") ||
457
+ lowerFieldName.includes("comment_id") ||
458
+ lowerFieldName.includes("workspace_id") ||
459
+ lowerFieldName.includes("notion") ||
460
+ // Check schema description for UUID hints
461
+ (schema.description &&
462
+ (schema.description.toLowerCase().includes("uuid") ||
463
+ schema.description
464
+ .toLowerCase()
465
+ .includes("universally unique")));
466
+ if (requiresUuid) {
467
+ // Always return a valid UUID for UUID-required fields
468
+ return variant === "empty"
469
+ ? "00000000-0000-0000-0000-000000000000" // Nil UUID
470
+ : "550e8400-e29b-41d4-a716-446655440000"; // Valid UUID v4
471
+ }
472
+ return variant === "empty"
473
+ ? "1" // Minimal non-empty ID to avoid creating invalid entities
474
+ : variant === "maximum"
475
+ ? "very_long_identifier_string_for_testing_maximum_length_handling_in_system"
476
+ : this.REALISTIC_DATA.ids[Math.floor(Math.random() * this.REALISTIC_DATA.ids.length)];
477
+ }
478
+ if (lowerFieldName.includes("name") ||
479
+ lowerFieldName.includes("title") ||
480
+ lowerFieldName.includes("label")) {
481
+ return variant === "empty"
482
+ ? "a" // Minimal non-empty value to avoid breaking search functionality
483
+ : variant === "maximum"
484
+ ? "Very Long Name For Testing Maximum String Length Handling In The System"
485
+ : variant === "special"
486
+ ? "Name with Special™ Characters® and Émojis 🎉"
487
+ : this.REALISTIC_DATA.names[Math.floor(Math.random() * this.REALISTIC_DATA.names.length)];
488
+ }
489
+ if (lowerFieldName.includes("date") ||
490
+ lowerFieldName.includes("time")) {
491
+ return variant === "empty" ? "" : this.REALISTIC_DATA.timestamps[0];
492
+ }
493
+ // Default string value - try to be contextual
494
+ return variant === "empty"
495
+ ? ""
496
+ : variant === "maximum"
497
+ ? "x".repeat(100)
498
+ : variant === "special"
499
+ ? 'Special chars: !@#$%^&*()_+-=[]{}|;:",.<>?/~`'
500
+ : "test"; // Simple, generic test value that often works
501
+ case "number":
502
+ case "integer":
503
+ if (variant === "maximum") {
504
+ return schema.maximum || 999999;
505
+ }
506
+ if (variant === "empty") {
507
+ return schema.minimum || 0;
508
+ }
509
+ // Context-aware number generation
510
+ if (lowerFieldName.includes("port")) {
511
+ return 8080;
512
+ }
513
+ if (lowerFieldName.includes("timeout") ||
514
+ lowerFieldName.includes("delay")) {
515
+ return 5000; // milliseconds
516
+ }
517
+ if (lowerFieldName.includes("count") ||
518
+ lowerFieldName.includes("limit")) {
519
+ return 10;
520
+ }
521
+ if (lowerFieldName.includes("page") ||
522
+ lowerFieldName.includes("offset")) {
523
+ return 0;
524
+ }
525
+ if (lowerFieldName.includes("size") ||
526
+ lowerFieldName.includes("length")) {
527
+ return 100;
528
+ }
529
+ return schema.minimum || 1;
530
+ case "boolean":
531
+ return variant === "empty" ? false : true;
532
+ case "array":
533
+ if (variant === "empty") {
534
+ // For mutation tools with array inputs, empty arrays are valid but useless for testing
535
+ // Generate one minimal item instead to make the test meaningful
536
+ const isMutationField = lowerFieldName.includes("entities") ||
537
+ lowerFieldName.includes("relations") ||
538
+ lowerFieldName.includes("observations") ||
539
+ lowerFieldName.includes("documents");
540
+ if (isMutationField && schema.items) {
541
+ // Generate one minimal item even for "empty" variant
542
+ const item = this.generateValueFromSchema(schema.items, "empty");
543
+ return [item];
544
+ }
545
+ return [];
546
+ }
547
+ if (variant === "maximum") {
548
+ // Generate multiple items
549
+ const count = 10;
550
+ if (schema.items) {
551
+ return Array(count)
552
+ .fill(0)
553
+ .map(() => this.generateValueFromSchema(schema.items, variant));
554
+ }
555
+ return Array(count)
556
+ .fill(0)
557
+ .map((_, i) => `item_${i}`);
558
+ }
559
+ // Typical variant - generate realistic array
560
+ if (schema.items) {
561
+ // Generate 1-2 items based on schema.items
562
+ const item = this.generateValueFromSchema(schema.items, variant);
563
+ return [item];
564
+ }
565
+ // Context-aware array generation (fallback for simple arrays without schema.items)
566
+ if (lowerFieldName.includes("tag") ||
567
+ lowerFieldName.includes("label")) {
568
+ return ["tag1", "tag2", "tag3"];
569
+ }
570
+ if (lowerFieldName.includes("id")) {
571
+ return ["id_1", "id_2", "id_3"];
572
+ }
573
+ return this.REALISTIC_DATA.arrays[1];
574
+ case "object":
575
+ // Don't return empty object for "empty" variant
576
+ // Let it fall through to generate minimal object properties
577
+ // This avoids creating objects with no required fields
578
+ if (variant === "maximum") {
579
+ return this.REALISTIC_DATA.jsonObjects[4]; // deeply nested
580
+ }
581
+ // Context-aware object generation
582
+ if (lowerFieldName.includes("config") ||
583
+ lowerFieldName.includes("settings")) {
584
+ return variant === "empty"
585
+ ? { enabled: false }
586
+ : { enabled: true, timeout: 5000, retries: 3 };
587
+ }
588
+ if (lowerFieldName.includes("metadata") ||
589
+ lowerFieldName.includes("meta")) {
590
+ return variant === "empty"
591
+ ? { version: "1.0.0" }
592
+ : {
593
+ created: new Date().toISOString(),
594
+ version: "1.0.0",
595
+ author: "test",
596
+ };
597
+ }
598
+ if (lowerFieldName.includes("filter") ||
599
+ lowerFieldName.includes("query")) {
600
+ return variant === "empty"
601
+ ? { limit: 1 }
602
+ : { status: "active", type: "user", limit: 10 };
603
+ }
604
+ return variant === "empty"
605
+ ? { id: 1 }
606
+ : this.REALISTIC_DATA.jsonObjects[0];
607
+ default:
608
+ // Return safe default instead of null to prevent tool crashes
609
+ return "test";
610
+ }
611
+ }
612
+ /**
613
+ * Check if tool has string inputs
614
+ */
615
+ static hasStringInputs(tool) {
616
+ if (!tool.inputSchema || tool.inputSchema.type !== "object") {
617
+ return false;
618
+ }
619
+ const properties = tool.inputSchema.properties || {};
620
+ for (const schema of Object.values(properties)) {
621
+ if (schema.type === "string") {
622
+ return true;
623
+ }
624
+ }
625
+ return false;
626
+ }
627
+ /**
628
+ * Generate a single realistic value for backward compatibility
629
+ */
630
+ static generateSingleValue(fieldName, schema) {
631
+ return this.generateRealisticValue(fieldName, schema, "typical");
632
+ }
633
+ /**
634
+ * Generate value from JSON schema definition
635
+ */
636
+ static generateValueFromSchema(schema, variant) {
637
+ if (!schema || !schema.type) {
638
+ // Return safe default instead of null to prevent tool crashes
639
+ return "test";
640
+ }
641
+ switch (schema.type) {
642
+ case "object": {
643
+ const obj = {};
644
+ if (schema.properties) {
645
+ for (const [key, propSchema] of Object.entries(schema.properties)) {
646
+ obj[key] = this.generateRealisticValue(key, propSchema, variant);
647
+ }
648
+ }
649
+ return obj;
650
+ }
651
+ case "array":
652
+ if (schema.items) {
653
+ const item = this.generateValueFromSchema(schema.items, variant);
654
+ return [item];
655
+ }
656
+ return [];
657
+ case "string":
658
+ return variant === "empty" ? "" : "test";
659
+ case "number":
660
+ case "integer":
661
+ return variant === "empty" ? 0 : 1;
662
+ case "boolean":
663
+ return variant === "empty" ? false : true;
664
+ default:
665
+ // Return safe default instead of null to prevent tool crashes
666
+ return "test";
667
+ }
668
+ }
669
+ }