Skip to main content
Glama

Dataverse MCP Server

by mwhesse
test-auth.cjs12.8 kB
#!/usr/bin/env node /** * Authentication Test Script for Dataverse MCP Server * This script tests authentication using credentials from .env.localtest */ const fs = require('fs'); const path = require('path'); const https = require('https'); const { URLSearchParams } = require('url'); // Function to load environment variables from a specific file function loadEnvFile(filePath) { if (!fs.existsSync(filePath)) { console.error(`❌ Environment file not found: ${filePath}`); console.log(`📝 Please create ${filePath} with your Dataverse credentials.`); console.log(`💡 You can copy from .env.localtest.example: cp .env.localtest.example ${filePath}`); process.exit(1); } const envContent = fs.readFileSync(filePath, 'utf8'); const envVars = {}; envContent.split('\n').forEach(line => { line = line.trim(); if (line && !line.startsWith('#')) { const [key, ...valueParts] = line.split('='); if (key && valueParts.length > 0) { envVars[key.trim()] = valueParts.join('=').trim(); } } }); return envVars; } // Function to validate required environment variables function validateEnvironment(envVars) { const required = [ 'DATAVERSE_URL', 'DATAVERSE_CLIENT_ID', 'DATAVERSE_CLIENT_SECRET', 'DATAVERSE_TENANT_ID' ]; const missing = required.filter(key => !envVars[key]); if (missing.length > 0) { console.error(`❌ Missing required environment variables: ${missing.join(', ')}`); console.log(`📝 Please add these variables to .env.localtest`); return false; } // Validate URL format if (!envVars.DATAVERSE_URL.startsWith('https://')) { console.error(`❌ DATAVERSE_URL must start with https://`); return false; } // Validate GUID format for IDs (basic check) const guidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; if (!guidRegex.test(envVars.DATAVERSE_CLIENT_ID)) { console.warn(`⚠️ DATAVERSE_CLIENT_ID doesn't look like a valid GUID`); } if (!guidRegex.test(envVars.DATAVERSE_TENANT_ID)) { console.warn(`⚠️ DATAVERSE_TENANT_ID doesn't look like a valid GUID`); } return true; } // Function to make HTTP request function makeRequest(options, postData = null) { return new Promise((resolve, reject) => { const req = https.request(options, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { try { const jsonData = JSON.parse(data); resolve({ statusCode: res.statusCode, data: jsonData, headers: res.headers, rawData: data }); } catch (e) { resolve({ statusCode: res.statusCode, data: data, headers: res.headers, rawData: data }); } }); }); req.on('error', (error) => { reject(error); }); if (postData) { req.write(postData); } req.end(); }); } // Function to test Azure AD authentication async function testAuthentication(envVars) { console.log('🔐 Testing Azure AD Authentication...'); const tokenUrl = `https://login.microsoftonline.com/${envVars.DATAVERSE_TENANT_ID}/oauth2/v2.0/token`; const params = new URLSearchParams(); params.append('grant_type', 'client_credentials'); params.append('client_id', envVars.DATAVERSE_CLIENT_ID); params.append('client_secret', envVars.DATAVERSE_CLIENT_SECRET); params.append('scope', `${envVars.DATAVERSE_URL}/.default`); const postData = params.toString(); const options = { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': Buffer.byteLength(postData) } }; try { const url = new URL(tokenUrl); options.hostname = url.hostname; options.path = url.pathname + url.search; const response = await makeRequest(options, postData); if (response.statusCode === 200 && response.data.access_token) { console.log('✅ Azure AD Authentication successful!'); console.log(` Token Type: ${response.data.token_type}`); console.log(` Expires In: ${response.data.expires_in} seconds`); console.log(` Token Preview: ${response.data.access_token.substring(0, 50)}...`); return response.data.access_token; } else { console.error('❌ Azure AD Authentication failed!'); console.error(` Status Code: ${response.statusCode}`); console.error(` Error: ${response.data.error || 'Unknown error'}`); console.error(` Description: ${response.data.error_description || 'No description'}`); console.error(` Raw Response: ${response.rawData || JSON.stringify(response.data)}`); return null; } } catch (error) { console.error('❌ Azure AD Authentication error!'); console.error(` Error: ${error.message}`); return null; } } // Function to test Dataverse API access async function testDataverseAccess(envVars, accessToken) { console.log('\n🌐 Testing Dataverse API Access...'); const apiUrl = `${envVars.DATAVERSE_URL}/api/data/v9.2/EntityDefinitions?$select=LogicalName,DisplayName`; try { const url = new URL(apiUrl); const options = { hostname: url.hostname, path: url.pathname + url.search, method: 'GET', headers: { 'Authorization': `Bearer ${accessToken}`, 'Accept': 'application/json', 'OData-MaxVersion': '4.0', 'OData-Version': '4.0' } }; const response = await makeRequest(options); if (response.statusCode === 200 && response.data.value) { console.log('✅ Dataverse API Access successful!'); console.log(` Retrieved ${response.data.value.length} entities:`); response.data.value.forEach((entity, index) => { const displayName = entity.DisplayName?.UserLocalizedLabel?.Label || entity.LogicalName; console.log(` ${index + 1}. ${entity.LogicalName} (${displayName})`); }); return true; } else { console.error('❌ Dataverse API Access failed!'); console.error(` Status Code: ${response.statusCode}`); if (response.data.error) { console.error(` Error Code: ${response.data.error.code}`); console.error(` Error Message: ${response.data.error.message}`); } console.error(` Raw Response: ${response.rawData || JSON.stringify(response.data)}`); return false; } } catch (error) { console.error('❌ Dataverse API Access error!'); console.error(` Error: ${error.message}`); return false; } } // Function to test WhoAmI API async function testWhoAmI(envVars, accessToken) { console.log('\n👤 Testing WhoAmI API...'); const whoAmIUrl = `${envVars.DATAVERSE_URL}/api/data/v9.2/WhoAmI`; try { const url = new URL(whoAmIUrl); const options = { hostname: url.hostname, path: url.pathname, method: 'GET', headers: { 'Authorization': `Bearer ${accessToken}`, 'Accept': 'application/json', 'OData-MaxVersion': '4.0', 'OData-Version': '4.0' } }; const response = await makeRequest(options); if (response.statusCode === 200) { console.log('✅ WhoAmI API call successful!'); console.log('📋 Current User Information:'); console.log(` User ID: ${response.data.UserId || 'N/A'}`); console.log(` Business Unit ID: ${response.data.BusinessUnitId || 'N/A'}`); console.log(` Organization ID: ${response.data.OrganizationId || 'N/A'}`); console.log('\n📄 Full WhoAmI Response:'); console.log(JSON.stringify(response.data, null, 2)); return true; } else { console.error('❌ WhoAmI API call failed!'); console.error(` Status Code: ${response.statusCode}`); if (response.data.error) { console.error(` Error Code: ${response.data.error.code}`); console.error(` Error Message: ${response.data.error.message}`); } console.error(` Raw Response: ${response.rawData || JSON.stringify(response.data)}`); return false; } } catch (error) { console.error('❌ WhoAmI API call error!'); console.error(` Error: ${error.message}`); return false; } } // Function to test specific permissions async function testPermissions(envVars, accessToken) { console.log('\n🔒 Testing Dataverse Permissions...'); // Test metadata access (required for schema operations) const metadataUrl = `${envVars.DATAVERSE_URL}/api/data/v9.2/EntityDefinitions?$select=LogicalName&$filter=IsCustomEntity eq true`; try { const url = new URL(metadataUrl); const options = { hostname: url.hostname, path: url.pathname + url.search, method: 'GET', headers: { 'Authorization': `Bearer ${accessToken}`, 'Accept': 'application/json', 'OData-MaxVersion': '4.0', 'OData-Version': '4.0' } }; const response = await makeRequest(options); if (response.statusCode === 200) { console.log('✅ Metadata access permissions verified!'); console.log(' ✓ Can read entity definitions'); console.log(' ✓ Can filter custom entities'); console.log(' ✓ Ready for schema operations'); return true; } else if (response.statusCode === 403) { console.error('❌ Insufficient permissions!'); console.error(' The app registration needs System Administrator role in Dataverse'); console.error(' Please check the SETUP_GUIDE.md for permission configuration'); return false; } else { console.error('❌ Permission test failed!'); console.error(` Status Code: ${response.statusCode}`); console.error(` Raw Response: ${response.rawData || JSON.stringify(response.data)}`); return false; } } catch (error) { console.error('❌ Permission test error!'); console.error(` Error: ${error.message}`); return false; } } // Main function async function main() { console.log('🧪 Dataverse Authentication Test'); console.log('=================================\n'); // Load environment variables from .env.localtest const envFilePath = path.join(__dirname, '.env.localtest'); console.log(`📁 Loading environment from: ${envFilePath}`); const envVars = loadEnvFile(envFilePath); console.log('✅ Environment file loaded successfully'); // Validate environment variables console.log('🔍 Validating environment variables...'); if (!validateEnvironment(envVars)) { process.exit(1); } console.log('✅ Environment validation passed'); // Display configuration (masked) console.log('\n📋 Configuration:'); console.log(` DATAVERSE_URL: ${envVars.DATAVERSE_URL}`); console.log(` DATAVERSE_CLIENT_ID: ${envVars.DATAVERSE_CLIENT_ID.substring(0, 8)}...`); console.log(` DATAVERSE_CLIENT_SECRET: ${'*'.repeat(20)}`); console.log(` DATAVERSE_TENANT_ID: ${envVars.DATAVERSE_TENANT_ID.substring(0, 8)}...`); console.log('\n🚀 Starting Authentication Tests...\n'); // Test 1: Azure AD Authentication const accessToken = await testAuthentication(envVars); if (!accessToken) { console.log('\n❌ Authentication test failed. Please check your credentials.'); process.exit(1); } // Test 2: WhoAmI API Test const whoAmI = await testWhoAmI(envVars, accessToken); if (!whoAmI) { console.log('\n❌ WhoAmI test failed. Please check your API access.'); process.exit(1); } // Test 3: Dataverse API Access const apiAccess = await testDataverseAccess(envVars, accessToken); if (!apiAccess) { console.log('\n❌ API access test failed. Please check your Dataverse URL and permissions.'); process.exit(1); } // Test 4: Permissions Check const permissions = await testPermissions(envVars, accessToken); if (!permissions) { console.log('\n❌ Permission test failed. Please check your app registration permissions.'); process.exit(1); } // Success summary console.log('\n🎉 All Authentication Tests Passed!'); console.log('====================================='); console.log('✅ Azure AD authentication working'); console.log('✅ WhoAmI API call successful'); console.log('✅ Dataverse API access confirmed'); console.log('✅ Schema operation permissions verified'); console.log('\n💡 Your credentials are ready for the MCP server!'); console.log('🚀 You can now run: npm run test:server'); } // Run the script if (require.main === module) { main().catch(error => { console.error('\n💥 Unexpected error:', error.message); process.exit(1); }); } module.exports = { loadEnvFile, validateEnvironment, testAuthentication, testDataverseAccess, testWhoAmI, testPermissions };

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/mwhesse/mcp-dataverse'

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