Skip to main content
Glama

Financial Modeling Prep MCP Server

Apache 2.0
17
59
  • Linux
  • Apple
verify-installation-methods.ts12.4 kB
#!/usr/bin/env tsx /** * Installation Method Verification Script * * Simplified verification script that tests core installation functionality * without requiring external dependencies like Docker or network access. */ import { spawn } from 'child_process'; import { existsSync, readFileSync } from 'fs'; import { join } from 'path'; /** * Verification configuration. */ const VERIFICATION_CONFIG = { /** * Test timeout for operations. */ TIMEOUT: 30000, /** * Required files for installation. */ REQUIRED_FILES: [ 'package.json', 'dist/index.js', 'README.md', 'LICENSE', 'server.json' ], /** * Expected CLI help patterns. */ HELP_PATTERNS: [ /Financial Modeling Prep MCP Server/i, /--fmp-token/i, /--port/i, /--help/i ], /** * Expected server startup patterns. */ STARTUP_PATTERNS: [ /MCP Server started successfully/i, /port \d+/i ] } as const; /** * Installation method verifier. */ class InstallationVerifier { private results: Array<{ test: string; status: 'PASS' | 'FAIL' | 'SKIP'; message: string }> = []; /** * Executes a command and returns the result. * @param command - Command to execute. * @param args - Command arguments. * @param options - Execution options. * @returns Promise resolving to execution result. */ private async executeCommand( command: string, args: string[], options: { cwd?: string; timeout?: number; env?: Record<string, string>; } = {} ): Promise<{ exitCode: number; stdout: string; stderr: string }> { const { cwd = process.cwd(), timeout = VERIFICATION_CONFIG.TIMEOUT, env = {} } = options; return new Promise((resolve) => { const child = spawn(command, args, { cwd, stdio: ['pipe', 'pipe', 'pipe'], env: { ...process.env, ...env } }); let stdout = ''; let stderr = ''; child.stdout?.on('data', (data) => { stdout += data.toString(); }); child.stderr?.on('data', (data) => { stderr += data.toString(); }); const timeoutId = setTimeout(() => { child.kill('SIGTERM'); resolve({ exitCode: 1, stdout, stderr: stderr + ' (timeout)' }); }, timeout); child.on('close', (code) => { clearTimeout(timeoutId); resolve({ exitCode: code || 0, stdout, stderr }); }); }); } /** * Spawns a process and waits for specific patterns. * @param command - Command to spawn. * @param args - Command arguments. * @param patterns - Patterns to wait for. * @param options - Spawn options. * @returns Promise resolving when patterns are matched. */ private async spawnAndWaitForPatterns( command: string, args: string[], patterns: RegExp[], options: { cwd?: string; timeout?: number; env?: Record<string, string>; } = {} ): Promise<{ matched: boolean; output: string }> { const { cwd = process.cwd(), timeout = VERIFICATION_CONFIG.TIMEOUT, env = {} } = options; return new Promise((resolve) => { const child = spawn(command, args, { cwd, env: { ...process.env, ...env }, stdio: ['pipe', 'pipe', 'pipe'] }); let output = ''; let matched = false; const checkPatterns = () => { const matchedPatterns = patterns.filter(pattern => pattern.test(output)); if (matchedPatterns.length === patterns.length) { matched = true; child.kill('SIGTERM'); resolve({ matched: true, output }); } }; child.stdout?.on('data', (data) => { output += data.toString(); checkPatterns(); }); child.stderr?.on('data', (data) => { output += data.toString(); checkPatterns(); }); child.on('close', () => { if (!matched) { resolve({ matched: false, output }); } }); setTimeout(() => { if (!matched) { child.kill('SIGTERM'); resolve({ matched: false, output }); } }, timeout); }); } /** * Records a test result. * @param test - Test name. * @param status - Test status. * @param message - Test message. */ private recordResult(test: string, status: 'PASS' | 'FAIL' | 'SKIP', message: string): void { this.results.push({ test, status, message }); const icon = status === 'PASS' ? '✅' : status === 'FAIL' ? '❌' : '⏭️'; console.log(`${icon} ${test}: ${message}`); } /** * Verifies required files exist. */ private async verifyRequiredFiles(): Promise<void> { console.log('\n🔍 Verifying required files...'); const missingFiles = VERIFICATION_CONFIG.REQUIRED_FILES.filter(file => !existsSync(file)); if (missingFiles.length === 0) { this.recordResult('Required Files', 'PASS', 'All required files present'); } else { this.recordResult('Required Files', 'FAIL', `Missing files: ${missingFiles.join(', ')}`); } } /** * Verifies package.json configuration. */ private async verifyPackageJson(): Promise<void> { console.log('\n📦 Verifying package.json configuration...'); try { if (!existsSync('package.json')) { this.recordResult('Package.json', 'FAIL', 'package.json not found'); return; } const packageJson = JSON.parse(readFileSync('package.json', 'utf-8')); const requiredFields = ['name', 'version', 'mcpName', 'main', 'bin']; const missingFields = requiredFields.filter(field => !packageJson[field]); if (missingFields.length === 0) { this.recordResult('Package.json Fields', 'PASS', 'All required fields present'); } else { this.recordResult('Package.json Fields', 'FAIL', `Missing fields: ${missingFields.join(', ')}`); } // Verify mcpName format if (packageJson.mcpName === 'io.github.imbenrabi/financial-modeling-prep-mcp-server') { this.recordResult('MCP Name', 'PASS', 'Correct MCP name format'); } else { this.recordResult('MCP Name', 'FAIL', `Invalid MCP name: ${packageJson.mcpName}`); } // Verify binary configuration if (packageJson.bin && packageJson.bin['fmp-mcp']) { this.recordResult('Binary Config', 'PASS', 'Binary configuration present'); } else { this.recordResult('Binary Config', 'FAIL', 'Missing binary configuration'); } } catch (error) { this.recordResult('Package.json', 'FAIL', `Error reading package.json: ${error}`); } } /** * Verifies CLI help functionality. */ private async verifyCLIHelp(): Promise<void> { console.log('\n💬 Verifying CLI help functionality...'); try { const result = await this.executeCommand('node', ['dist/index.js', '--help']); if (result.exitCode === 0) { const output = result.stdout + result.stderr; const matchedPatterns = VERIFICATION_CONFIG.HELP_PATTERNS.filter(pattern => pattern.test(output)); if (matchedPatterns.length === VERIFICATION_CONFIG.HELP_PATTERNS.length) { this.recordResult('CLI Help', 'PASS', 'Help output contains all expected patterns'); } else { this.recordResult('CLI Help', 'FAIL', `Missing help patterns: ${VERIFICATION_CONFIG.HELP_PATTERNS.length - matchedPatterns.length}`); } } else { this.recordResult('CLI Help', 'FAIL', `Help command failed with exit code ${result.exitCode}`); } } catch (error) { this.recordResult('CLI Help', 'FAIL', `Error executing help command: ${error}`); } } /** * Verifies server startup functionality. */ private async verifyServerStartup(): Promise<void> { console.log('\n🚀 Verifying server startup...'); try { const { matched, output } = await this.spawnAndWaitForPatterns( 'node', ['dist/index.js', '--fmp-token', 'test_token', '--port', '8084'], //@ts-ignore VERIFICATION_CONFIG.STARTUP_PATTERNS ); if (matched) { this.recordResult('Server Startup', 'PASS', 'Server started successfully with expected output'); } else { this.recordResult('Server Startup', 'FAIL', 'Server startup patterns not found in output'); } } catch (error) { this.recordResult('Server Startup', 'FAIL', `Error starting server: ${error}`); } } /** * Verifies NPM package structure. */ private async verifyNPMPackage(): Promise<void> { console.log('\n📋 Verifying NPM package structure...'); try { // Check if package can be packed const result = await this.executeCommand('npm', ['pack', '--dry-run']); if (result.exitCode === 0) { this.recordResult('NPM Pack', 'PASS', 'Package can be packed successfully'); } else { this.recordResult('NPM Pack', 'FAIL', `NPM pack failed: ${result.stderr}`); } } catch (error) { this.recordResult('NPM Pack', 'FAIL', `Error testing NPM pack: ${error}`); } } /** * Verifies build artifacts. */ private async verifyBuildArtifacts(): Promise<void> { console.log('\n🔨 Verifying build artifacts...'); if (existsSync('dist/index.js')) { try { // Try to require the built file to check for syntax errors const result = await this.executeCommand('node', ['-c', 'dist/index.js']); if (result.exitCode === 0) { this.recordResult('Build Artifacts', 'PASS', 'Built files are syntactically valid'); } else { this.recordResult('Build Artifacts', 'FAIL', `Built file has syntax errors: ${result.stderr}`); } } catch (error) { this.recordResult('Build Artifacts', 'FAIL', `Error checking build artifacts: ${error}`); } } else { this.recordResult('Build Artifacts', 'FAIL', 'dist/index.js not found'); } } /** * Generates a summary report. */ private generateReport(): void { console.log('\n📊 Installation Verification Summary'); console.log('====================================='); const passed = this.results.filter(r => r.status === 'PASS').length; const failed = this.results.filter(r => r.status === 'FAIL').length; const skipped = this.results.filter(r => r.status === 'SKIP').length; const total = this.results.length; console.log(`Total Tests: ${total}`); console.log(`Passed: ${passed}`); console.log(`Failed: ${failed}`); console.log(`Skipped: ${skipped}`); console.log(`Success Rate: ${((passed / (total - skipped)) * 100).toFixed(1)}%`); if (failed > 0) { console.log('\n❌ Failed Tests:'); this.results .filter(r => r.status === 'FAIL') .forEach(r => console.log(` • ${r.test}: ${r.message}`)); } console.log(`\nTimestamp: ${new Date().toISOString()}`); if (failed === 0) { console.log('\n🎉 All installation methods verified successfully!'); console.log('The Financial Modeling Prep MCP Server is ready for registry publishing.'); } else { console.log('\n⚠️ Some verification tests failed. Please review and fix the issues above.'); } } /** * Runs all verification tests. */ async run(): Promise<void> { console.log('🔍 Starting Installation Method Verification'); console.log('==========================================='); try { await this.verifyRequiredFiles(); await this.verifyPackageJson(); await this.verifyBuildArtifacts(); await this.verifyCLIHelp(); await this.verifyServerStartup(); await this.verifyNPMPackage(); } catch (error) { console.error('💥 Verification failed with error:', error); } finally { this.generateReport(); const failed = this.results.filter(r => r.status === 'FAIL').length; process.exit(failed === 0 ? 0 : 1); } } } /** * Main execution function. */ async function main(): Promise<void> { const verifier = new InstallationVerifier(); await verifier.run(); } // Handle CLI execution if (import.meta.url === `file://${process.argv[1]}`) { main().catch((error) => { console.error('💥 Fatal error:', error); process.exit(1); }); } export { InstallationVerifier };

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/imbenrabi/Financial-Modeling-Prep-MCP-Server'

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