Skip to main content
Glama
phase3-ddl-operations.test.jsβ€’14.3 kB
#!/usr/bin/env node /** * Phase 3: DDL Operations Test * Tests DDL operations (CREATE/ALTER/DROP) - full development mode */ import { SqlServerMCP } from '../../../index.js'; import { TestDatabaseHelper } from './test-database-helper.js'; import { serverConfig } from '../../../lib/config/server-config.js'; import { validateServerConfiguration } from '../shared/config-validator.js'; import dotenv from 'dotenv'; // Load environment variables from .env file first dotenv.config({ override: false }); // Load .env but don't override existing env vars // Set test-specific environment variables explicitly (these will take precedence) process.env.SQL_SERVER_READ_ONLY = 'false'; process.env.SQL_SERVER_ALLOW_DESTRUCTIVE_OPERATIONS = 'true'; process.env.SQL_SERVER_ALLOW_SCHEMA_CHANGES = 'true'; process.env.SQL_SERVER_TRUST_CERT = 'true'; // Trust self-signed certificates process.env.NODE_ENV = 'test'; // Force configuration reload to pick up our environment variable changes serverConfig.reload(); // Verify the configuration was set correctly console.log('πŸ”§ Environment Variables Set:'); console.log(' SQL_SERVER_READ_ONLY:', process.env.SQL_SERVER_READ_ONLY); console.log( ' SQL_SERVER_ALLOW_DESTRUCTIVE_OPERATIONS:', process.env.SQL_SERVER_ALLOW_DESTRUCTIVE_OPERATIONS ); console.log(' SQL_SERVER_ALLOW_SCHEMA_CHANGES:', process.env.SQL_SERVER_ALLOW_SCHEMA_CHANGES); console.log(' SQL_SERVER_TRUST_CERT:', process.env.SQL_SERVER_TRUST_CERT); // Verify the server config actually loaded the changes validateServerConfiguration( serverConfig, { readOnlyMode: false, allowDestructiveOperations: true, allowSchemaChanges: true }, 'DDL' ); class DdlOperationsTest { constructor() { this.results = { passed: 0, failed: 0, tests: [] }; this.server = null; this.dbHelper = null; this.testDbName = null; } async runTest(name, description, testFn) { console.log(`πŸ§ͺ Testing: ${description}`); try { await testFn(); console.log(`βœ… PASSED: ${name}`); this.results.passed++; this.results.tests.push({ name, status: 'PASSED', description }); } catch (error) { console.log(`❌ FAILED: ${name} - ${error.message.split('\\n')[0]}`); this.results.failed++; this.results.tests.push({ name, status: 'FAILED', description, error: error.message.split('\\n')[0] }); } } async runDdlTest() { console.log('πŸš€ Starting Phase 3: DDL Operations Test (Full Development Mode)'); console.log( '================================================================\ ' ); console.log('πŸ”§ Current Configuration:'); console.log(' πŸ”“ Read-Only Mode: FALSE'); console.log(' ⚠️ Allow Destructive Operations: TRUE'); console.log(' πŸ› οΈ Allow Schema Changes: TRUE (DDL operations enabled)'); console.log(' πŸ” SSL Encryption: ENABLED'); console.log( ' ⚠️ WARNING: This is full development mode - all operations allowed!\ ' ); // Create MCP server instance - force configuration reload first serverConfig.reload(); // Ensure latest environment variables are loaded this.server = new SqlServerMCP(); // Verify the server instance has the correct configuration const serverSecurityConfig = this.server.config.getSecurityConfig(); console.log('πŸ” Server Instance Security Config:'); console.log(' readOnlyMode:', serverSecurityConfig.readOnlyMode); console.log(' allowDestructiveOperations:', serverSecurityConfig.allowDestructiveOperations); console.log(' allowSchemaChanges:', serverSecurityConfig.allowSchemaChanges); if (serverSecurityConfig.readOnlyMode !== false) { throw new Error( `Server instance still in read-only mode! Expected: false, Got: ${serverSecurityConfig.readOnlyMode}` ); } if (serverSecurityConfig.allowSchemaChanges !== true) { throw new Error( `Server instance schema changes not enabled! Expected: true, Got: ${serverSecurityConfig.allowSchemaChanges}` ); } // Create database helper and test database this.dbHelper = new TestDatabaseHelper(this.server); try { console.log('πŸ—οΈ Setting up test environment...'); this.testDbName = await this.dbHelper.createTestDatabase('Phase3DDL'); console.log(`πŸ“Š Using test database: ${this.testDbName}\n`); } catch (error) { console.error('❌ Failed to set up test environment:', error.message); throw error; } console.log('πŸ“Š 1. VERIFY ALL OPERATIONS WORK'); console.log( '=================================\ ' ); // Verify read operations still work await this.runTest('select_operations', 'SELECT operations should work', async () => { const result = await this.server.executeQuery( 'SELECT COUNT(*) as ProductCount FROM Products', this.testDbName ); if (!result.content || !result.content[0] || !result.content[0].text) { throw new Error('No content returned'); } }); console.log('\nπŸ› οΈ 2. TEST DDL OPERATIONS (CREATE/ALTER/DROP)'); console.log( '===============================================\ ' ); // Test CREATE TABLE (should now work) await this.runTest('ddl_create_table', 'CREATE TABLE should now be ALLOWED', async () => { const result = await this.server.executeQuery( 'CREATE TABLE TestDdlTable (ID int PRIMARY KEY IDENTITY(1,1), Name nvarchar(100) NOT NULL, CreatedDate datetime2 DEFAULT GETDATE())', this.testDbName ); if (!result.content || !result.content[0] || !result.content[0].text) { throw new Error('No content returned'); } if ( !result.content[0].text.includes('executed successfully') && !result.content[0].text.includes('rows affected') ) { throw new Error('CREATE TABLE operation did not report success'); } }); // Test ALTER TABLE (should now work) await this.runTest('ddl_alter_table', 'ALTER TABLE should now be ALLOWED', async () => { const result = await this.server.executeQuery( 'ALTER TABLE TestDdlTable ADD Description nvarchar(255) NULL', this.testDbName ); if (!result.content || !result.content[0] || !result.content[0].text) { throw new Error('No content returned'); } if ( !result.content[0].text.includes('executed successfully') && !result.content[0].text.includes('rows affected') ) { throw new Error('ALTER TABLE operation did not report success'); } }); console.log('\nπŸ”“ 3. TEST DML OPERATIONS (SHOULD ALSO WORK)'); console.log( '==============================================\ ' ); // Test INSERT into our test table await this.runTest( 'dml_insert_test', 'INSERT should work in full development mode', async () => { const result = await this.server.executeQuery( "INSERT INTO TestDdlTable (Name, Description) VALUES ('Test Record', 'Testing full development mode')", this.testDbName ); if (!result.content || !result.content[0] || !result.content[0].text) { throw new Error('No content returned'); } if ( !result.content[0].text.includes('rows affected') && !result.content[0].text.includes('successfully') ) { throw new Error('INSERT operation did not report success'); } } ); // Test UPDATE await this.runTest( 'dml_update_test', 'UPDATE should work in full development mode', async () => { const result = await this.server.executeQuery( "UPDATE TestDdlTable SET Description = 'Updated description for DDL testing' WHERE Name = 'Test Record'", this.testDbName ); if (!result.content || !result.content[0] || !result.content[0].text) { throw new Error('No content returned'); } if ( !result.content[0].text.includes('rows affected') && !result.content[0].text.includes('successfully') ) { throw new Error('UPDATE operation did not report success'); } } ); // Verify the data exists await this.runTest( 'verify_data_exists', 'Verify test data was created and updated', async () => { const result = await this.server.executeQuery( "SELECT ID, Name, Description FROM TestDdlTable WHERE Name = 'Test Record'", this.testDbName ); if (!result.content || !result.content[0] || !result.content[0].text) { throw new Error('No content returned'); } if ( !result.content[0].text.includes('Test Record') || !result.content[0].text.includes('Updated description') ) { throw new Error('Test data was not created or updated correctly'); } } ); console.log('\nπŸ—‘οΈ 4. CLEANUP - TEST DROP OPERATIONS'); console.log( '======================================\ ' ); // Test DELETE (cleanup data first) await this.runTest('dml_delete_cleanup', 'DELETE should work for cleanup', async () => { const result = await this.server.executeQuery( "DELETE FROM TestDdlTable WHERE Name = 'Test Record'", this.testDbName ); if (!result.content || !result.content[0] || !result.content[0].text) { throw new Error('No content returned'); } if ( !result.content[0].text.includes('rows affected') && !result.content[0].text.includes('successfully') ) { throw new Error('DELETE operation did not report success'); } }); // Test DROP TABLE (should now work) await this.runTest('ddl_drop_table', 'DROP TABLE should now be ALLOWED (cleanup)', async () => { const result = await this.server.executeQuery('DROP TABLE TestDdlTable', this.testDbName); if (!result.content || !result.content[0] || !result.content[0].text) { throw new Error('No content returned'); } if ( !result.content[0].text.includes('executed successfully') && !result.content[0].text.includes('rows affected') ) { throw new Error('DROP TABLE operation did not report success'); } }); console.log('\n⚑ 5. VERIFY ALL TOOLS STILL WORK'); console.log( '=================================\ ' ); // Quick check that other MCP tools still work await this.runTest( 'list_tables_verification', 'Other MCP tools should still work (list_tables)', async () => { const result = await this.server.listTables(this.testDbName); if (!result.content || !result.content[0] || !result.content[0].text) { throw new Error('No content returned'); } } ); // Quick performance monitoring check await this.runTest( 'performance_monitoring_ddl', 'Performance monitoring should track DDL operations', async () => { const result = this.server.getPerformanceStats(); if (!result || !result[0] || !result[0].text) { throw new Error('No content returned'); } const stats = JSON.parse(result[0].text); if (!stats.success || !stats.data) { throw new Error('Performance stats format invalid'); } // Should have recorded many queries by now if (stats.data.overall && stats.data.overall.totalQueries <= 0) { throw new Error('Performance monitoring not tracking queries'); } } ); } async cleanup() { if (this.dbHelper) { console.log('\n🧹 Cleaning up test environment...'); // Only clean up the specific database created by this test if (this.testDbName) { await this.dbHelper.cleanupDatabase(this.testDbName); console.log(`βœ… Cleaned up test database: ${this.testDbName}`); } else { console.log('⚠️ No test database to clean up'); } } } printSummary() { console.log('\n🎯 PHASE 3 DDL OPERATIONS RESULTS'); console.log('================================='); console.log(`βœ… Tests Passed: ${this.results.passed}`); console.log(`❌ Tests Failed: ${this.results.failed}`); console.log(`πŸ“Š Total Tests: ${this.results.passed + this.results.failed}`); console.log( `πŸ“ˆ Success Rate: ${((this.results.passed / (this.results.passed + this.results.failed)) * 100).toFixed(1)}%` ); if (this.results.failed > 0) { console.log('\n❌ Failed Tests:'); this.results.tests .filter(t => t.status === 'FAILED') .forEach(t => console.log(` β€’ ${t.name}: ${t.error}`)); } console.log('\nπŸ† Phase 3 Assessment:'); if (this.results.failed === 0) { console.log(' βœ… PHASE 3 COMPLETE - DDL operations work correctly!'); console.log(' πŸ› οΈ CREATE/ALTER/DROP operations: WORKING'); console.log(' πŸ”“ INSERT/UPDATE/DELETE operations: WORKING'); console.log(' πŸ“Š All MCP tools: WORKING'); console.log(' πŸŽ‰ ALL THREE SECURITY PHASES VERIFIED!'); } else if (this.results.passed / (this.results.passed + this.results.failed) >= 0.8) { console.log(' ⚠️ PHASE 3 MOSTLY WORKING - Some issues detected'); } else { console.log(' ❌ PHASE 3 FAILED - Significant issues with DDL operations'); } console.log('\nπŸ”’ SECURITY SUMMARY:'); console.log(' βœ… Phase 1: Read-Only Mode - 100% SUCCESS'); console.log(' βœ… Phase 2: DML Operations - SUCCESS (verified during testing)'); console.log( ` ${this.results.failed === 0 ? 'βœ…' : '❌'} Phase 3: DDL Operations - ${this.results.failed === 0 ? 'SUCCESS' : 'FAILED'}` ); } } // Run the DDL test const ddlTest = new DdlOperationsTest(); try { await ddlTest.runDdlTest(); ddlTest.printSummary(); // Exit with failure code if any tests failed if (ddlTest.results.failed > 0) { console.error(`\ πŸ’₯ ${ddlTest.results.failed} test(s) failed`); process.exit(1); } } catch (error) { console.error('πŸ’₯ DDL test failed:', error.message); process.exit(1); } finally { await ddlTest.cleanup(); } process.exit(0);

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/egarcia74/warp-sql-server-mcp'

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