Skip to main content
Glama
portel-dev

NCP - Natural Context Provider

by portel-dev
test-confirm-pattern-fast.js5.46 kB
#!/usr/bin/env node /** * Fast confirm-pattern test using cached embeddings * Uses existing embeddings from ~/.ncp.backup/embeddings.json */ import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); // Load transformer.js const { pipeline } = await import('@xenova/transformers'); console.log('\n🧪 Testing Confirm-Before-Run Pattern (Fast Mode)\n'); // Load cached embeddings const embeddingsPath = path.join(process.env.HOME, '.ncp.backup', 'embeddings.json'); console.log(`Loading cached embeddings from: ${embeddingsPath}`); const embeddings = JSON.parse(fs.readFileSync(embeddingsPath, 'utf-8')); const toolCount = Object.keys(embeddings).length; console.log(`✓ Loaded ${toolCount} cached tool embeddings\n`); // Load the pattern const pattern = 'operations that delete files, remove data permanently, create or write files to disk, send emails or messages, post or publish content online, execute shell commands or scripts, modify database records, deploy or push to production, make HTTP POST PUT or DELETE requests, update or patch existing data, drop or truncate tables, commit or push to git repositories, transfer money or charge payments, revoke access or permissions, or make any changes that cannot be easily undone'; console.log(`Pattern: ${pattern.substring(0, 100)}...\n`); // Create embedding for pattern console.log('Creating pattern embedding...'); const model = await pipeline('feature-extraction', 'Xenova/all-MiniLM-L6-v2', { quantized: true }); const patternEmbedding = await model(pattern, { pooling: 'mean', normalize: true }); console.log('✓ Pattern embedding created\n'); // Cosine similarity helper function cosineSimilarity(a, b) { let dotProduct = 0; let normA = 0; let normB = 0; for (let i = 0; i < a.length; i++) { dotProduct += Number(a[i]) * Number(b[i]); normA += Number(a[i]) * Number(a[i]); normB += Number(b[i]) * Number(b[i]); } return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB)); } // Test thresholds const thresholds = [0.50, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80]; console.log(`Testing ${thresholds.length} threshold levels: ${thresholds.join(', ')}\n`); // Calculate similarities console.log('Calculating similarities...'); const results = []; for (const [toolId, toolData] of Object.entries(embeddings)) { const toolEmbedding = new Float32Array(toolData.embedding); const confidence = cosineSimilarity(patternEmbedding.data, toolEmbedding); results.push({ toolId, toolName: toolData.toolName, description: toolData.description || '', confidence, thresholdResults: thresholds.map(t => confidence >= t ? 'YES' : 'NO') }); } console.log(`✓ Analyzed ${results.length} tools\n`); // CSV escape helper function escapeCsv(field) { if (field.includes(',') || field.includes('"') || field.includes('\n')) { return `"${field.replace(/"/g, '""')}"`; } return field; } // Generate CSV const csvRows = []; const thresholdHeaders = thresholds.map(t => `Trigger_${t.toFixed(2)}`).join(','); csvRows.push(`MCP,Tool,Description,Confidence,${thresholdHeaders}`); for (const result of results) { const [mcpName, toolName] = result.toolId.split(':'); csvRows.push([ escapeCsv(mcpName || ''), escapeCsv(toolName || result.toolId), escapeCsv(result.description), result.confidence.toFixed(4), ...result.thresholdResults ].join(',')); } // Write CSV const outputPath = './confirm-pattern-results.csv'; fs.writeFileSync(outputPath, csvRows.join('\n'), 'utf-8'); console.log(`✓ Results written to ${outputPath}\n`); // Display statistics console.log('📊 Statistics by Threshold:\n'); console.log(` Total tools: ${results.length}\n`); thresholds.forEach(thresh => { const triggeredCount = results.filter(r => r.confidence >= thresh).length; const percentage = (triggeredCount / results.length * 100).toFixed(1); console.log(` Threshold ${thresh.toFixed(2)}: ${triggeredCount} tools triggered (${percentage}%)`); }); console.log(); // Show top 10 console.log('🔝 Top 10 Most Likely Modifier Operations:\n'); const sorted = results.sort((a, b) => b.confidence - a.confidence).slice(0, 10); sorted.forEach((t, index) => { const confidencePercent = Math.round(t.confidence * 100); console.log(` ${index + 1}. ${t.toolId} ${confidencePercent}%`); console.log(` ${t.description.substring(0, 80)}${t.description.length > 80 ? '...' : ''}`); }); console.log(); // Recommend threshold console.log('💡 Threshold Recommendation:\n'); let recommendedThreshold = thresholds[0]; for (const thresh of thresholds) { const triggeredCount = results.filter(r => r.confidence >= thresh).length; const percentage = triggeredCount / results.length; if (percentage >= 0.10 && percentage <= 0.30) { recommendedThreshold = thresh; break; } } const recommendedCount = results.filter(r => r.confidence >= recommendedThreshold).length; const recommendedPercentage = (recommendedCount / results.length * 100).toFixed(1); console.log(` Recommended: ${recommendedThreshold.toFixed(2)}`); console.log(` Would trigger: ${recommendedCount} tools (${recommendedPercentage}%)`); console.log(` Rationale: Balances safety (catches dangerous operations) with usability (avoids too many prompts)\n`); console.log('💡 Review the CSV file to analyze all results in detail\n');

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/portel-dev/ncp'

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