Skip to main content
Glama
validate-extension.js3.8 kB
#!/usr/bin/env node import * as fs from 'fs'; import * as path from 'path'; // Check if a file path was provided if (process.argv.length < 3) { console.error('Usage: node validate-extension.js <path-to-blah.json>'); process.exit(1); } // Get the file path from command line args const configPath = process.argv[2]; // Ensure the file exists if (!fs.existsSync(configPath)) { console.error(`Error: File not found at ${configPath}`); process.exit(1); } // Read the file try { const configContent = fs.readFileSync(configPath, 'utf-8'); const config = JSON.parse(configContent); console.log('Successfully parsed configuration file'); // Check if the config has an extends property if (!config.extends || typeof config.extends !== 'object') { console.error('❌ No extends property found in the configuration'); process.exit(1); } console.log(`✅ Found extends property with ${Object.keys(config.extends).length} extensions`); // Get the base directory for resolving relative paths const baseDir = path.dirname(path.resolve(configPath)); // Check each extension for (const [name, extPath] of Object.entries(config.extends)) { console.log(`\nChecking extension: ${name} => ${extPath}`); if (!extPath || typeof extPath !== 'string') { console.error(`❌ Invalid extension path for ${name}`); continue; } // Skip URL paths if (extPath.startsWith('http://') || extPath.startsWith('https://')) { console.log(`✅ Valid URL path: ${extPath}`); console.log('ℹ️ Note: Cannot verify remote extension files'); continue; } // Resolve relative paths const resolvedPath = path.resolve(baseDir, extPath); console.log(`Resolved path: ${resolvedPath}`); // Check if the extension file exists if (!fs.existsSync(resolvedPath)) { console.error(`❌ Extension file not found: ${resolvedPath}`); continue; } try { // Try to parse the extension file const extContent = fs.readFileSync(resolvedPath, 'utf-8'); const extConfig = JSON.parse(extContent); console.log(`✅ Successfully parsed extension: ${name}`); // Check for basic properties if (!extConfig.name) { console.warn(`⚠️ Extension is missing 'name' property`); } if (!extConfig.version) { console.warn(`⚠️ Extension is missing 'version' property`); } // Check tools if (!Array.isArray(extConfig.tools)) { console.warn(`⚠️ Extension has no tools array`); } else { console.log(`ℹ️ Extension contains ${extConfig.tools.length} tools`); // Check for tool validity let validTools = 0; let invalidTools = 0; for (const tool of extConfig.tools) { if (!tool || typeof tool !== 'object') { invalidTools++; continue; } if (!tool.name) { console.warn(`⚠️ Tool missing 'name' property`); invalidTools++; } else { validTools++; } } console.log(`ℹ️ Valid tools: ${validTools}, Invalid tools: ${invalidTools}`); } // Check for circular extensions if (extConfig.extends && typeof extConfig.extends === 'object') { console.warn(`⚠️ Extension '${name}' has its own extends property, which may lead to circular references`); } } catch (error) { console.error(`❌ Error parsing extension ${name}: ${error.message}`); } } console.log('\n✅ Extension validation complete'); } catch (error) { console.error(`Error parsing configuration: ${error.message}`); process.exit(1); }

Latest Blog Posts

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/thomasdavis/blah'

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