@boundless-oss/atlas
Version:
Atlas - MCP Server for comprehensive startup project management
116 lines (97 loc) • 3.93 kB
text/typescript
import { describe, it, expect } from 'vitest';
import { promises as fs } from 'fs';
import path from 'path';
interface Tool {
name: string;
description: string;
inputSchema?: {
type: string;
properties?: Record<string, any>;
required?: string[];
};
}
describe('Tool Schema Validation', () => {
it('should have required field for all tools with properties in inputSchema', async () => {
const toolsWithMissingRequired: Array<{ file: string; tool: string; line?: number }> = [];
// Read all module files and find tool definitions
const modulesDir = path.join(process.cwd(), 'src/modules');
const moduleFiles = await fs.readdir(modulesDir, { recursive: true });
for (const file of moduleFiles) {
if (typeof file === 'string' && file.endsWith('index.ts') && !file.includes('__tests__')) {
const filePath = path.join(modulesDir, file);
const content = await fs.readFile(filePath, 'utf-8');
const lines = content.split('\n');
// Find tool definitions
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
// Look for tool definitions
if (line.includes('name:') && line.includes("'") && i > 0 && lines[i-1].includes('{')) {
const toolNameMatch = line.match(/name:\s*['"]([^'"]+)['"]/);
if (toolNameMatch) {
const toolName = toolNameMatch[1];
// Look for inputSchema
let j = i + 1;
let hasInputSchema = false;
let hasProperties = false;
let hasRequired = false;
let braceCount = 1;
while (j < lines.length && braceCount > 0) {
const currentLine = lines[j];
if (currentLine.includes('inputSchema:')) {
hasInputSchema = true;
}
if (hasInputSchema && currentLine.includes('properties:')) {
hasProperties = true;
}
if (hasInputSchema && currentLine.includes('required:')) {
hasRequired = true;
}
// Count braces to know when tool definition ends
braceCount += (currentLine.match(/\{/g) || []).length;
braceCount -= (currentLine.match(/\}/g) || []).length;
j++;
}
if (hasInputSchema && hasProperties && !hasRequired) {
toolsWithMissingRequired.push({
file: file,
tool: toolName,
line: i + 1
});
}
}
}
}
}
}
// This test should fail initially, showing which tools are missing the required field
if (toolsWithMissingRequired.length > 0) {
console.log('\nTools missing required field:');
toolsWithMissingRequired.forEach(({ file, tool, line }) => {
console.log(` - ${file}: ${tool} (line ~${line})`);
});
}
expect(toolsWithMissingRequired).toHaveLength(0);
});
it('should be able to reproduce the JSON Schema validation error', () => {
// Example of a schema that would fail validation
const invalidSchema = {
type: 'object',
properties: {
name: { type: 'string' },
age: { type: 'number' }
}
// Missing required field
};
const validSchema = {
type: 'object',
properties: {
name: { type: 'string' },
age: { type: 'number' }
},
required: [] // Even empty array is valid
};
// This demonstrates the issue - schemas with properties should have required field
expect(invalidSchema).not.toHaveProperty('required');
expect(validSchema).toHaveProperty('required');
});
});