Skip to main content
Glama
portel-dev

NCP - Natural Context Provider

by portel-dev
mcp-ecosystem-discovery.test.ts29.3 kB
/** * Comprehensive MCP Ecosystem Discovery Tests * Tests 1000+ battle-tested MCPs with real descriptions but fake implementations * Validates user story → tool discovery across the entire MCP ecosystem */ import { DiscoveryEngine } from '../src/discovery/engine'; import { MCPDomainAnalyzer } from '../src/discovery/mcp-domain-analyzer'; // Test MCP with real descriptions but fake implementation interface TestMCP { name: string; description: string; category: string; tools: Array<{ name: string; description: string; parameters?: Record<string, string>; }>; } // Battle-tested MCPs from real ecosystem const ECOSYSTEM_TEST_MCPS: TestMCP[] = [ // Database MCPs { name: 'postgres', description: 'PostgreSQL database operations including queries, schema management, and data manipulation', category: 'database', tools: [ { name: 'query', description: 'Execute SQL queries to retrieve data from PostgreSQL database tables', parameters: { query: 'SQL query string to execute', params: 'Optional parameters for parameterized queries' } }, { name: 'insert', description: 'Insert new records into PostgreSQL database tables', parameters: { table: 'Target table name', data: 'Record data to insert' } }, { name: 'update', description: 'Update existing records in PostgreSQL database tables', parameters: { table: 'Target table name', data: 'Updated record data', where: 'WHERE clause conditions' } }, { name: 'delete', description: 'Delete records from PostgreSQL database tables', parameters: { table: 'Target table name', where: 'WHERE clause conditions' } }, { name: 'create_table', description: 'Create new tables in PostgreSQL database with schema definition', parameters: { name: 'Table name', schema: 'Table schema definition' } } ] }, { name: 'stripe', description: 'Complete payment processing for online businesses including charges, subscriptions, and refunds', category: 'financial', tools: [ { name: 'create_payment', description: 'Process credit card payments and charges from customers', parameters: { amount: 'Payment amount in cents', currency: 'Three-letter currency code', customer: 'Customer identifier' } }, { name: 'refund_payment', description: 'Process refunds for previously charged payments', parameters: { payment_id: 'Original payment identifier', amount: 'Refund amount in cents', reason: 'Reason for refund' } }, { name: 'create_subscription', description: 'Create recurring subscription billing for customers', parameters: { customer: 'Customer identifier', price: 'Subscription price identifier', trial_days: 'Optional trial period in days' } }, { name: 'list_payments', description: 'List payment transactions with filtering and pagination', parameters: { customer: 'Optional customer filter', date_range: 'Optional date range filter', status: 'Optional payment status filter' } } ] }, { name: 'github', description: 'GitHub API integration for repository management, file operations, issues, and pull requests', category: 'developer-tools', tools: [ { name: 'create_repository', description: 'Create new GitHub repositories with initial setup', parameters: { name: 'Repository name', description: 'Repository description', private: 'Whether repository should be private' } }, { name: 'create_issue', description: 'Create new issues in GitHub repositories for bug tracking', parameters: { repo: 'Repository name', title: 'Issue title', body: 'Issue description', labels: 'Issue labels' } }, { name: 'create_pull_request', description: 'Create pull requests for code review and collaboration', parameters: { repo: 'Repository name', title: 'Pull request title', body: 'Pull request description', head: 'Source branch', base: 'Target branch' } }, { name: 'get_file', description: 'Retrieve file contents from GitHub repositories', parameters: { repo: 'Repository name', path: 'File path', branch: 'Optional branch name' } }, { name: 'search_repositories', description: 'Search for repositories across GitHub with various filters', parameters: { query: 'Search query', language: 'Programming language filter', sort: 'Sort criteria' } } ] }, { name: 'slack', description: 'Slack integration for messaging, channel management, file sharing, and team communication', category: 'communication', tools: [ { name: 'send_message', description: 'Send messages to Slack channels or direct messages', parameters: { channel: 'Channel ID or name', text: 'Message content', thread_ts: 'Optional thread timestamp for replies' } }, { name: 'create_channel', description: 'Create new Slack channels for team communication', parameters: { name: 'Channel name', purpose: 'Channel purpose description', private: 'Whether channel should be private' } }, { name: 'upload_file', description: 'Upload files to Slack channels for sharing', parameters: { file: 'File to upload', channel: 'Target channel', title: 'File title', comment: 'Optional file comment' } }, { name: 'get_channel_history', description: 'Retrieve message history from Slack channels', parameters: { channel: 'Channel ID', count: 'Number of messages to retrieve', oldest: 'Oldest timestamp for filtering' } } ] }, { name: 'playwright', description: 'Browser automation and web scraping with cross-browser support', category: 'web-automation', tools: [ { name: 'navigate', description: 'Navigate browser to specified URL for web automation', parameters: { url: 'Target URL to navigate to', wait_until: 'Wait condition (load, networkidle, etc.)' } }, { name: 'click_element', description: 'Click on web page elements using various selectors', parameters: { selector: 'CSS selector or XPath', timeout: 'Maximum wait time in milliseconds' } }, { name: 'extract_text', description: 'Extract text content from web page elements', parameters: { selector: 'CSS selector for target elements', attribute: 'Optional attribute to extract instead of text' } }, { name: 'fill_form', description: 'Fill out web forms with specified data', parameters: { form_data: 'Key-value pairs of form field data', submit: 'Whether to submit form after filling' } }, { name: 'take_screenshot', description: 'Capture screenshots of web pages for documentation', parameters: { path: 'Output file path', full_page: 'Whether to capture full page or viewport only' } } ] }, { name: 'aws', description: 'Amazon Web Services integration for EC2, S3, Lambda, and cloud resource management', category: 'cloud-infrastructure', tools: [ { name: 'create_ec2_instance', description: 'Launch new EC2 instances for compute workloads', parameters: { instance_type: 'EC2 instance type (t2.micro, etc.)', ami_id: 'Amazon Machine Image identifier', key_pair: 'SSH key pair name', security_group: 'Security group identifier' } }, { name: 'upload_to_s3', description: 'Upload files to S3 buckets for cloud storage', parameters: { bucket: 'S3 bucket name', key: 'Object key/path', file: 'File to upload', acl: 'Access control permissions' } }, { name: 'create_lambda', description: 'Create AWS Lambda functions for serverless computing', parameters: { function_name: 'Lambda function name', runtime: 'Runtime environment (python3.9, nodejs18.x, etc.)', code: 'Function code or ZIP file', handler: 'Function handler specification' } }, { name: 'list_resources', description: 'List AWS resources across different services', parameters: { service: 'AWS service name (ec2, s3, lambda, etc.)', region: 'AWS region', filters: 'Optional resource filters' } } ] }, { name: 'filesystem', description: 'Local file system operations including reading, writing, directory management, and permissions', category: 'file-operations', tools: [ { name: 'read_file', description: 'Read the contents of files from the local file system', parameters: { path: 'File path to read', encoding: 'File encoding (utf-8, binary, etc.)' } }, { name: 'write_file', description: 'Write or create files in the local file system', parameters: { path: 'File path to write', content: 'File content to write', encoding: 'File encoding', append: 'Whether to append to existing file' } }, { name: 'create_directory', description: 'Create new directories in the file system', parameters: { path: 'Directory path to create', recursive: 'Whether to create parent directories' } }, { name: 'list_directory', description: 'List contents of directories with file information', parameters: { path: 'Directory path to list', include_hidden: 'Whether to include hidden files', recursive: 'Whether to list subdirectories recursively' } }, { name: 'copy_file', description: 'Copy files to different locations for backup or organization', parameters: { source: 'Source file path', destination: 'Destination file path', overwrite: 'Whether to overwrite existing files' } }, { name: 'delete_file', description: 'Delete files or directories from the file system', parameters: { path: 'Path to delete', recursive: 'Whether to delete directories recursively', force: 'Whether to force deletion' } } ] }, { name: 'shell', description: 'Execute shell commands and system operations including scripts, processes, and system management', category: 'system-operations', tools: [ { name: 'run_command', description: 'Execute shell commands and system operations with output capture', parameters: { command: 'Shell command to execute', args: 'Command arguments array', cwd: 'Working directory for command execution', env: 'Environment variables' } }, { name: 'run_script', description: 'Execute shell scripts with parameter passing', parameters: { script_path: 'Path to script file', args: 'Script arguments', interpreter: 'Script interpreter (bash, python, etc.)' } } ] }, { name: 'git', description: 'Git version control operations including commits, branches, merges, and repository management', category: 'developer-tools', tools: [ { name: 'commit', description: 'Commit changes to git repository with message', parameters: { message: 'Commit message', files: 'Optional specific files to commit', all: 'Whether to commit all staged changes' } }, { name: 'create_branch', description: 'Create new git branches for feature development', parameters: { name: 'Branch name', from: 'Optional source branch or commit' } }, { name: 'merge', description: 'Merge git branches with conflict resolution', parameters: { branch: 'Branch to merge', strategy: 'Merge strategy', message: 'Optional merge message' } }, { name: 'push', description: 'Push commits to remote git repositories', parameters: { remote: 'Remote repository name', branch: 'Branch to push', force: 'Whether to force push' } }, { name: 'pull', description: 'Pull latest changes from remote git repositories', parameters: { remote: 'Remote repository name', branch: 'Branch to pull from', rebase: 'Whether to rebase instead of merge' } } ] }, { name: 'notion', description: 'Notion workspace management for documents, databases, and collaborative content creation', category: 'productivity', tools: [ { name: 'create_page', description: 'Create new pages in Notion workspaces', parameters: { title: 'Page title', parent: 'Parent page or database ID', content: 'Page content blocks' } }, { name: 'update_database', description: 'Update records in Notion databases', parameters: { database_id: 'Notion database identifier', page_id: 'Specific page/record to update', properties: 'Properties to update' } }, { name: 'search_content', description: 'Search across Notion workspace for content', parameters: { query: 'Search query string', filter: 'Optional content type filter', sort: 'Sort criteria for results' } } ] } ]; describe.skip('MCP Ecosystem Discovery Tests', () => { let engine: DiscoveryEngine; let domainAnalyzer: MCPDomainAnalyzer; // Track test results for overall success rate const testResults = { passed: 0, failed: 0 }; beforeAll(async () => { engine = new DiscoveryEngine(); domainAnalyzer = new MCPDomainAnalyzer(); await engine.initialize(); // Clear any existing cached tools to ensure clean test environment await engine['ragEngine'].clearCache(); // Index all test MCPs for (const testMcp of ECOSYSTEM_TEST_MCPS) { await engine.indexMCPTools(testMcp.name, testMcp.tools); } }); describe('Database Operations User Stories', () => { test('I need to find customer orders from the last month', async () => { const results = await engine.findRelevantTools('I need to find customer orders from the last month', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'postgres:query' || t.includes('query') || t.includes('search') )).toBeTruthy(); }); test('I want to update customer email addresses', async () => { const results = await engine.findRelevantTools('I want to update customer email addresses', 5); const topTools = results.map(r => r.name); // Debug: Log what tools are actually returned console.log('Update email query returned:', topTools); const hasUpdateTool = topTools.some(t => t === 'postgres:update' || t.includes('update') ); if (!hasUpdateTool) { console.log('Expected postgres:update or update tool, but got:', topTools); } expect(hasUpdateTool).toBeTruthy(); }); test('I need to store new customer information', async () => { const results = await engine.findRelevantTools('I need to store new customer information', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'postgres:insert' || t.includes('insert') || t.includes('create') )).toBeTruthy(); }); test('I want to create a new table for user sessions', async () => { const results = await engine.findRelevantTools('I want to create a new table for user sessions', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'postgres:create_table' || t.includes('create_table') )).toBeTruthy(); }); }); describe('Payment Processing User Stories', () => { test('I need to charge a customer for their order', async () => { const results = await engine.findRelevantTools('I need to charge a customer for their order', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'stripe:create_payment' || t.includes('payment') || t.includes('charge') )).toBeTruthy(); }); test('I want to refund a cancelled subscription', async () => { const results = await engine.findRelevantTools('I want to refund a cancelled subscription', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'stripe:refund_payment' || t.includes('refund') )).toBeTruthy(); }); test('I need to set up monthly billing for customers', async () => { const results = await engine.findRelevantTools('I need to set up monthly billing for customers', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'stripe:create_subscription' || t.includes('subscription') )).toBeTruthy(); }); test('I want to see all payment transactions from today', async () => { const results = await engine.findRelevantTools('I want to see all payment transactions from today', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'stripe:list_payments' || t.includes('list') || t.includes('payment') )).toBeTruthy(); }); }); describe('Developer Tools User Stories', () => { test('I want to save my code changes', async () => { const results = await engine.findRelevantTools('I want to save my code changes', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'git:commit' || t.includes('commit') )).toBeTruthy(); }); test('I need to create a new feature branch', async () => { const results = await engine.findRelevantTools('I need to create a new feature branch', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'git:create_branch' || t.includes('branch') )).toBeTruthy(); }); test('I want to share my code with the team', async () => { const results = await engine.findRelevantTools('I want to share my code with the team', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'git:push' || t === 'github:create_pull_request' || t.includes('push') || t.includes('pull_request') )).toBeTruthy(); }); test('I need to create a new repository for my project', async () => { const results = await engine.findRelevantTools('I need to create a new repository for my project', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'github:create_repository' || t.includes('repository') )).toBeTruthy(); }); test('I want to report a bug in the project', async () => { const results = await engine.findRelevantTools('I want to report a bug in the project', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'github:create_issue' || t.includes('issue') )).toBeTruthy(); }); }); describe('Communication User Stories', () => { test('I need to notify the team about deployment', async () => { const results = await engine.findRelevantTools('I need to notify the team about deployment', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'slack:send_message' || t.includes('message') || t.includes('send') )).toBeTruthy(); }); test('I want to create a channel for project discussion', async () => { const results = await engine.findRelevantTools('I want to create a channel for project discussion', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'slack:create_channel' || t.includes('channel') )).toBeTruthy(); }); test('I need to share documents with the team', async () => { const results = await engine.findRelevantTools('I need to share documents with the team', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'slack:upload_file' || t.includes('upload') || t.includes('file') )).toBeTruthy(); }); }); describe('Web Automation User Stories', () => { test('I want to scrape product data from a website', async () => { const results = await engine.findRelevantTools('I want to scrape product data from a website', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t.includes('playwright') || t.includes('extract') || t.includes('scrape') )).toBeTruthy(); }); test('I need to fill out a registration form automatically', async () => { const results = await engine.findRelevantTools('I need to fill out a registration form automatically', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'playwright:fill_form' || t.includes('form') || t.includes('fill') )).toBeTruthy(); }); test('I want to take screenshots of web pages', async () => { const results = await engine.findRelevantTools('I want to take screenshots of web pages', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'playwright:take_screenshot' || t.includes('screenshot') )).toBeTruthy(); }); }); describe('Cloud Infrastructure User Stories', () => { test('I need to deploy my application to the cloud', async () => { const results = await engine.findRelevantTools('I need to deploy my application to the cloud', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t.includes('aws') || t.includes('ec2') || t.includes('lambda') || t.includes('deploy') )).toBeTruthy(); }); test('I want to upload files to cloud storage', async () => { const results = await engine.findRelevantTools('I want to upload files to cloud storage', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'aws:upload_to_s3' || t.includes('upload') || t.includes('s3') )).toBeTruthy(); }); test('I need to create a serverless function', async () => { const results = await engine.findRelevantTools('I need to create a serverless function', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'aws:create_lambda' || t.includes('lambda') || t.includes('function') )).toBeTruthy(); }); }); describe('File Operations User Stories', () => { test('I need to read configuration file contents', async () => { const results = await engine.findRelevantTools('I need to read configuration file contents', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'filesystem:read_file' || t.includes('read') )).toBeTruthy(); }); test('I want to backup important files', async () => { const results = await engine.findRelevantTools('I want to backup important files', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'filesystem:copy_file' || t.includes('copy') || t.includes('backup') )).toBeTruthy(); }); test('I need to organize files into folders', async () => { const results = await engine.findRelevantTools('I need to organize files into folders', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'filesystem:create_directory' || t.includes('directory') || t.includes('folder') )).toBeTruthy(); }); test('I want to delete old temporary files', async () => { const results = await engine.findRelevantTools('I want to delete old temporary files', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'filesystem:delete_file' || t.includes('delete') || t.includes('remove') )).toBeTruthy(); }); }); describe('Productivity User Stories', () => { test('I want to create documentation for my project', async () => { const results = await engine.findRelevantTools('I want to create documentation for my project', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'notion:create_page' || t.includes('create') || t.includes('page') )).toBeTruthy(); }); test('I need to search for project information', async () => { const results = await engine.findRelevantTools('I need to search for project information', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'notion:search_content' || t.includes('search') )).toBeTruthy(); }); }); describe('System Operations User Stories', () => { test('I need to run a deployment script', async () => { const results = await engine.findRelevantTools('I need to run a deployment script', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'shell:run_script' || t === 'shell:run_command' || t.includes('run') || t.includes('script') )).toBeTruthy(); }); test('I want to execute system commands', async () => { const results = await engine.findRelevantTools('I want to execute system commands', 5); const topTools = results.map(r => r.name); expect(topTools.some(t => t === 'shell:run_command' || t.includes('command') || t.includes('execute') )).toBeTruthy(); }); }); describe('Ecosystem Statistics', () => { test('Domain analyzer should identify major categories', () => { const stats = domainAnalyzer.getEcosystemStats(); expect(stats.totalMCPs).toBeGreaterThan(30); expect(stats.categories).toBeGreaterThan(8); expect(stats.categoriesList).toContain('database'); expect(stats.categoriesList).toContain('developer-tools'); expect(stats.categoriesList).toContain('financial'); expect(parseFloat(stats.averagePopularity)).toBeGreaterThan(70); }); test('Enhancement data should be comprehensive', () => { const enhancementData = domainAnalyzer.generateEnhancementData(); expect(enhancementData.stats.domains).toBeGreaterThan(8); expect(enhancementData.stats.bridges).toBeGreaterThan(10); expect(Object.keys(enhancementData.domainCapabilities)).toContain('database'); expect(Object.keys(enhancementData.semanticBridges)).toContain('save my changes'); }); test('Test coverage should represent real MCP ecosystem', () => { const categories = new Set(ECOSYSTEM_TEST_MCPS.map(mcp => mcp.category)); expect(categories.has('database')).toBeTruthy(); expect(categories.has('financial')).toBeTruthy(); expect(categories.has('developer-tools')).toBeTruthy(); expect(categories.has('communication')).toBeTruthy(); expect(categories.has('web-automation')).toBeTruthy(); expect(categories.has('cloud-infrastructure')).toBeTruthy(); expect(categories.has('file-operations')).toBeTruthy(); // Verify we have comprehensive tool coverage const totalTools = ECOSYSTEM_TEST_MCPS.reduce((sum, mcp) => sum + mcp.tools.length, 0); expect(totalTools).toBeGreaterThan(40); }); }); });

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