#!/usr/bin/env node
// Final test with corrected tool name after identifying the exact issue
const fetch = require('node-fetch');
const https = require('https');
const { spawn } = require('child_process');
const express = require('express');
const crypto = require('crypto');
// Disable SSL verification for local testing
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
const LOCAL_MCP_URL = 'https://localhost:3003';
function base64URLEncode(str) {
return str.toString('base64')
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
}
function generateCodeChallenge() {
const codeVerifier = base64URLEncode(crypto.randomBytes(32));
const codeChallenge = base64URLEncode(crypto.createHash('sha256').update(codeVerifier).digest());
return { codeVerifier, codeChallenge };
}
class FinalCorrectedTest {
constructor() {
this.username = 'david+allcloud@umbrellacost.com';
this.password = 'Dsamsung1!';
this.accessToken = null;
this.server = null;
this.port = 3006; // Different port to avoid conflicts
this.codeVerifier = null;
}
async startCallbackServer() {
return new Promise((resolve) => {
const app = express();
app.get('/', (req, res) => {
res.send(`
<html>
<head><title>Final Corrected Tool Test</title></head>
<body style="font-family: Arial; text-align: center; padding: 50px;">
<h1>🎯 Testing api__api_v2_recommendations_list</h1>
<p><strong>Final test with correct tool name</strong></p>
</body>
</html>
`);
});
app.get('/callback', (req, res) => {
const { code, error } = req.query;
if (error) {
res.send(`<html><body>Error: ${error}</body></html>`);
return;
}
if (code) {
res.send(`
<html>
<body style="font-family: Arial; text-align: center; padding: 50px;">
<h1 style="color: green;">✅ OAuth Success!</h1>
<p>Testing with correct tool name...</p>
<script>setTimeout(() => window.close(), 2000);</script>
</body>
</html>
`);
resolve(code);
}
});
this.server = app.listen(this.port, () => {
console.log(`📡 Callback server listening on port ${this.port}`);
});
});
}
async registerOAuthClient() {
const redirectUri = `http://localhost:${this.port}/callback`;
const clientData = {
client_name: 'Final Corrected Tool Test Client',
redirect_uris: [redirectUri],
grant_types: ['authorization_code'],
response_types: ['code'],
scope: 'openid profile email'
};
const response = await fetch(`${LOCAL_MCP_URL}/register`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(clientData),
agent: new https.Agent({
rejectUnauthorized: false
})
});
if (!response.ok) {
throw new Error(`Client registration failed: ${response.status}`);
}
const client = await response.json();
console.log(`✅ Client registered: ${client.client_id}`);
return { clientId: client.client_id, redirectUri };
}
async performOAuthFlow(clientId, redirectUri) {
const { codeVerifier, codeChallenge } = generateCodeChallenge();
this.codeVerifier = codeVerifier;
const authUrl = `${LOCAL_MCP_URL}/authorize?` + new URLSearchParams({
response_type: 'code',
client_id: clientId,
redirect_uri: redirectUri,
state: 'final_corrected_test',
code_challenge: codeChallenge,
code_challenge_method: 'S256',
scope: 'openid profile email'
});
console.log('🌐 Opening browser for authentication...');
this.openBrowser(authUrl);
return true;
}
openBrowser(url) {
const platform = process.platform;
let command;
if (platform === 'darwin') {
command = 'open';
} else if (platform === 'win32') {
command = 'start';
} else {
command = 'xdg-open';
}
spawn(command, [url], { detached: true, stdio: 'ignore' });
}
async exchangeCodeForToken(authorizationCode, clientId, redirectUri) {
const response = await fetch(`${LOCAL_MCP_URL}/oauth/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
grant_type: 'authorization_code',
code: authorizationCode,
redirect_uri: redirectUri,
client_id: clientId,
code_verifier: this.codeVerifier
}),
agent: new https.Agent({
rejectUnauthorized: false
})
});
if (response.ok) {
const tokenData = await response.json();
this.accessToken = tokenData.access_token;
console.log(`✅ Token obtained successfully`);
return tokenData;
} else {
const error = await response.text();
throw new Error(`Token exchange failed: ${error}`);
}
}
async makeApiCall(toolName, args, description) {
const request = {
jsonrpc: '2.0',
method: 'tools/call',
params: {
name: toolName,
arguments: args
},
id: Math.floor(Math.random() * 1000)
};
console.log(`📤 ${description}`);
console.log(` Tool Name: ${toolName}`);
console.log(` Arguments:`, JSON.stringify(args, null, 2));
const startTime = Date.now();
const response = await fetch(`${LOCAL_MCP_URL}/mcp`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.accessToken}`,
'Content-Type': 'application/json',
'Accept': 'application/json, text/event-stream'
},
body: JSON.stringify(request),
agent: new https.Agent({
rejectUnauthorized: false
})
});
const time = Date.now() - startTime;
if (!response.ok) {
console.log(`❌ ${description} FAILED: ${response.status}`);
const error = await response.text();
console.log(' Error:', error);
return null;
}
let data;
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('text/event-stream')) {
const responseText = await response.text();
const lines = responseText.split('\n');
for (const line of lines) {
if (line.startsWith('data: ')) {
const jsonStr = line.substring(6).trim();
if (jsonStr && jsonStr !== '[DONE]') {
try {
data = JSON.parse(jsonStr);
break;
} catch (parseError) {}
}
}
}
} else {
data = await response.json();
}
console.log(`✅ ${description} SUCCESS (${time}ms)`);
return data;
}
async runFinalTest() {
if (!this.accessToken) {
console.log('❌ No bearer token available');
return false;
}
console.log(`\n🎯 FINAL TEST: Corrected Tool Name`);
console.log(`🔑 Bearer Token: ${this.accessToken.substring(0, 50)}...`);
console.log(`\n🔧 Testing with CORRECT tool name: api__api_v2_recommendations_list`);
try {
// Test 1: Bank Leumi BL Test Env specific query
console.log('\n📍 TEST 1: Bank Leumi BL Test Env Query');
const recommendationsData = await this.makeApiCall('api__api_v2_recommendations_list', {
userQuery: 'show me recommendations for Bank Leumi BL Test Env',
filters: {
date_range: {
start_date: '2024-08-01',
end_date: '2024-12-31'
}
},
sort: [{
by: 'potential_savings',
order: 'desc'
}],
page_size: 25
}, 'Bank Leumi BL Test Env recommendations (CORRECT TOOL)');
if (recommendationsData) {
console.log('\n📊 RESULT ANALYSIS:');
if (recommendationsData.result && recommendationsData.result.content) {
const text = recommendationsData.result.content[0]?.text || '';
console.log('✅ Recommendations received successfully!');
console.log(`📄 Response length: ${text.length} characters`);
// Check for customer detection success
const customerMatch = text.match(/\*\*Customer:\*\* ([^\n]+)/);
if (customerMatch) {
console.log(`🎯 Detected Customer: ${customerMatch[1]}`);
if (customerMatch[1].includes('BL Test Env')) {
console.log(`✅ SUCCESS: Correctly identified BL Test Env!`);
} else {
console.log(`⚠️ Customer detected but not BL Test Env: ${customerMatch[1]}`);
}
}
// Check for recommendations content
const recsMatch = text.match(/Total Recommendations:\*\* (\d+)/);
if (recsMatch) {
console.log(`📊 Total Recommendations: ${recsMatch[1]}`);
}
// Show first part of response
console.log('\n📄 Response Preview:');
console.log(text.substring(0, 500) + '...');
} else {
console.log('❌ No content in recommendations response');
console.log('Full response:', JSON.stringify(recommendationsData, null, 2));
}
} else {
console.log('❌ No recommendations data received');
}
// Test 2: List available tools to confirm correct name
console.log('\n📍 TEST 2: List Available Tools');
const toolsData = await this.makeApiCall('tools/list', {}, 'List all available tools');
if (toolsData && toolsData.result && toolsData.result.tools) {
console.log('\n🔧 AVAILABLE RECOMMENDATION TOOLS:');
toolsData.result.tools
.filter(tool => tool.name.includes('recommendation'))
.forEach(tool => {
console.log(` ✅ ${tool.name}: ${tool.description}`);
});
}
console.log('\n✅ Final Test Complete!');
return true;
} catch (error) {
console.log('❌ Test Error:', error.message);
return false;
}
}
cleanup() {
if (this.server) {
this.server.close();
}
}
async run() {
try {
console.log('🎯 Final Corrected Tool Test Starting...\n');
const serverPromise = this.startCallbackServer();
const { clientId, redirectUri } = await this.registerOAuthClient();
const flowStarted = await this.performOAuthFlow(clientId, redirectUri);
if (!flowStarted) {
throw new Error('Failed to start OAuth flow');
}
console.log('⏳ Waiting for authentication...');
console.log(' Please login with: david+allcloud@umbrellacost.com');
const timeoutPromise = new Promise((_, reject) =>
setTimeout(() => reject(new Error('OAuth timeout after 5 minutes')), 300000)
);
const authorizationCode = await Promise.race([serverPromise, timeoutPromise]);
if (authorizationCode) {
const tokenData = await this.exchangeCodeForToken(authorizationCode, clientId, redirectUri);
if (tokenData) {
await this.runFinalTest();
}
}
} catch (error) {
console.error('❌ Error:', error.message);
} finally {
this.cleanup();
}
}
}
// Handle graceful shutdown
process.on('SIGINT', () => {
console.log('\n🛑 Interrupted - cleaning up...');
process.exit(0);
});
const test = new FinalCorrectedTest();
test.run();