Skip to main content
Glama
test-create-task-validation.ts10.4 kB
/** * Test Create Task Endpoint Validation * This test verifies that the generated MCP tool code for the Create Task endpoint * correctly matches the expected structure in createTaskValidation.json */ import path from 'path'; import { fileURLToPath } from 'url'; import fs from 'fs'; // Get the directory name const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); // Import the generateEndpointToolCode function import generateEndpointToolCode from '../build/services/generateEndpointToolCode.js'; import { validateMCPSchema } from '../src/utils/validateMCPSchema.js'; // Define the interface here to avoid import issues interface GenerateEndpointToolCodeParams { path: string; method: string; swaggerFilePath: string; includeApiInName?: boolean; includeVersionInName?: boolean; singularizeResourceNames?: boolean; } async function testCreateTaskEndpoint() { console.log('Testing Create Task Endpoint Code Generation...'); try { // Use the projects-api-v3 Swagger file from ReferenceFiles const swaggerFilePath = path.join(__dirname, '..', 'ReferenceFiles', 'projects-api-v3.oas2.yml'); if (!fs.existsSync(swaggerFilePath)) { console.error(`Swagger file not found at ${swaggerFilePath}`); return false; } console.log(`Using Swagger file: ${swaggerFilePath}`); // Define the Create Task endpoint const createTaskEndpoint = { path: '/projects/api/v3/tasklists/{tasklistId}/tasks.json', method: 'post', swaggerFilePath, includeApiInName: false, includeVersionInName: false, singularizeResourceNames: true }; console.log(`Generating tool code for ${createTaskEndpoint.method.toUpperCase()} ${createTaskEndpoint.path}...`); const tsCode = await generateEndpointToolCode(createTaskEndpoint); // Check if the response is a validation error message if (tsCode.includes('MCP Schema Validation Failed')) { console.error('MCP schema validation failed:'); console.error(tsCode); return false; } // Save the generated code for inspection const outputDir = path.join(__dirname, 'generated'); if (!fs.existsSync(outputDir)) { fs.mkdirSync(outputDir, { recursive: true }); } const outputPath = path.join(outputDir, 'create-task-endpoint.ts'); fs.writeFileSync(outputPath, tsCode); console.log(`Generated code saved to: ${outputPath}`); // Validate the generated code against the MCP schema const validationResult = validateMCPSchema(tsCode); if (!validationResult.isValid) { console.error('Generated code failed MCP schema validation:'); console.error(validationResult.errors); return false; } console.log('Generated code passed MCP schema validation!'); // Load the expected structure from createTaskValidation.json const expectedStructurePath = path.join(__dirname, 'test-data', 'createTaskValidation.json'); if (!fs.existsSync(expectedStructurePath)) { console.error(`Expected structure file not found at ${expectedStructurePath}`); console.error(`Current directory: ${__dirname}`); console.error(`Files in test-data directory:`); try { const testDataDir = path.join(__dirname, 'test-data'); if (fs.existsSync(testDataDir)) { const files = fs.readdirSync(testDataDir); files.forEach(file => console.error(`- ${file}`)); } else { console.error('test-data directory does not exist'); } } catch (err) { console.error('Error reading test-data directory:', err); } return false; } const expectedStructure = JSON.parse(fs.readFileSync(expectedStructurePath, 'utf8')); console.log('Loaded expected structure from createTaskValidation.json'); // Extract the inputSchema from the generated code const inputSchemaMatch = tsCode.match(/inputSchema:\s*({[\s\S]*?}),\s*required:/); if (!inputSchemaMatch) { console.error('Could not extract inputSchema from generated code'); return false; } // Save the raw inputSchema for debugging const rawInputSchemaPath = path.join(outputDir, 'raw-input-schema.txt'); fs.writeFileSync(rawInputSchemaPath, inputSchemaMatch[1]); console.log(`Raw inputSchema saved to: ${rawInputSchemaPath}`); // Instead of trying to parse the complex TypeScript code as JSON, // let's use a simpler approach to validate the structure console.log('Validating structure by checking for key properties...'); // Check for top-level properties from the expected structure const missingTopLevelProps = []; for (const key in expectedStructure) { const propRegex = new RegExp(`${key}:\\s*{`, 'i'); if (!propRegex.test(tsCode)) { missingTopLevelProps.push(key); } } if (missingTopLevelProps.length > 0) { console.error('❌ Missing top-level properties in the generated code:'); missingTopLevelProps.forEach(prop => { console.error(`- ${prop}`); }); return false; } console.log('✅ All top-level properties from the expected structure are present in the generated code'); // Check for some key nested properties const keyProps = [ 'name', 'description', 'tasklistId', 'assignees', 'reminders', 'tags', 'taskOptions' ]; const missingProps = []; for (const prop of keyProps) { // Use a simpler regex that just checks if the property exists anywhere in the code const propRegex = new RegExp(`${prop}:\\s*{`, 'i'); if (!propRegex.test(tsCode)) { missingProps.push(prop); } } if (missingProps.length > 0) { console.error('❌ Missing properties in the generated code:'); missingProps.forEach(prop => { console.error(`- ${prop}`); }); return false; } console.log('✅ All key properties are present in the generated code'); // If we've made it this far, the test passes return true; } catch (error: any) { console.error('Error testing Create Task endpoint:', error.message); if (error.stack) { console.error(error.stack); } return false; } } /** * Validates that the generated structure matches the expected structure * @param generated The generated structure from the inputSchema * @param expected The expected structure from createTaskValidation.json * @returns Validation result with errors if any */ function validateStructure(generated: any, expected: any, path = ''): { isValid: boolean; errors: string[] } { const errors: string[] = []; // Check if the expected structure is an object with properties if (typeof expected === 'object' && expected !== null && !Array.isArray(expected)) { // For each property in the expected structure for (const key in expected) { const currentPath = path ? `${path}.${key}` : key; // Check if the property exists in the generated structure if (!generated || !generated[key]) { errors.push(`Missing property: ${currentPath}`); continue; } // If the property is an object, recursively validate its structure if (typeof expected[key] === 'object' && expected[key] !== null && !Array.isArray(expected[key])) { // Check if the property is a type placeholder (e.g., "<string>", "<integer>") const isTypePlaceholder = Object.keys(expected[key]).some(k => typeof expected[key][k] === 'string' && expected[key][k].startsWith('<') && expected[key][k].endsWith('>') ); if (isTypePlaceholder) { // This is a type placeholder, so we don't need to validate its structure continue; } // For properties object in the generated schema if (generated[key].properties) { const nestedValidation = validateStructure(generated[key].properties, expected[key], currentPath); errors.push(...nestedValidation.errors); } // For items in arrays else if (generated[key].items && generated[key].items.properties) { const nestedValidation = validateStructure(generated[key].items.properties, expected[key], currentPath); errors.push(...nestedValidation.errors); } // For nested types else if (generated[key].type === 'object' && generated[key].properties) { const nestedValidation = validateStructure(generated[key].properties, expected[key], currentPath); errors.push(...nestedValidation.errors); } // If we can't find properties, it's an error else { errors.push(`Property ${currentPath} should be an object with properties`); } } // If the property is an array, check its items else if (Array.isArray(expected[key])) { // Check if the generated property is defined as an array if (generated[key].type !== 'array') { errors.push(`Property ${currentPath} should be an array`); continue; } // If the expected array has items, validate the first item's structure if (expected[key].length > 0 && typeof expected[key][0] === 'object') { // Check if the generated array has items defined if (!generated[key].items) { errors.push(`Property ${currentPath} should have items defined`); continue; } // If the items are objects, validate their structure if (generated[key].items.type === 'object' && generated[key].items.properties) { const nestedValidation = validateStructure(generated[key].items.properties, expected[key][0], `${currentPath}[0]`); errors.push(...nestedValidation.errors); } } } } } return { isValid: errors.length === 0, errors }; } // Run the test testCreateTaskEndpoint() .then(success => { if (success) { console.log('\n✅ Create Task endpoint test passed!'); process.exit(0); } else { console.error('\n❌ Create Task endpoint test failed!'); process.exit(1); } }) .catch(error => { console.error('Unhandled error:', error); process.exit(1); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Vizioz/Swagger-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server