Skip to main content
Glama

Financial Modeling Prep MCP Server

Apache 2.0
17
59
  • Linux
  • Apple
RegistryApiIntegration.test.ts17.9 kB
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import { readFile, writeFile, mkdir, rm } from 'fs/promises'; import { join } from 'path'; import { tmpdir } from 'os'; describe('RegistryApiIntegration', () => { let testDir: string; beforeEach(async () => { testDir = join(tmpdir(), `registry-api-test-${Date.now()}`); await mkdir(testDir, { recursive: true }); }); afterEach(async () => { await rm(testDir, { recursive: true, force: true }); }); /** * Creates test server.json and package.json files. */ async function createTestFiles(): Promise<void> { const packageJson = { name: 'financial-modeling-prep-mcp-server', version: '2.5.0', mcpName: 'io.github.imbenrabi/financial-modeling-prep-mcp-server', description: 'MCP server for Financial Modeling Prep API', repository: { type: 'git', url: 'https://github.com/imbenrabi/Financial-Modeling-Prep-MCP-Server' } }; const serverJson = { $schema: 'https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json', name: 'io.github.imbenrabi/financial-modeling-prep-mcp-server', description: 'MCP server for Financial Modeling Prep API with 250+ financial data tools', version: '2.5.0', status: 'active', packages: [ { registry_type: 'npm', registry_base_url: 'https://registry.npmjs.org', identifier: 'financial-modeling-prep-mcp-server', version: '2.5.0', runtime_hint: 'npx', transport: { type: 'streamable-http', url: 'https://financial-modeling-prep-mcp-server-production.up.railway.app/mcp' } } ], repository: { url: 'https://github.com/imbenrabi/Financial-Modeling-Prep-MCP-Server', source: 'github', id: '988409529' }, website_url: 'https://github.com/imbenrabi/Financial-Modeling-Prep-MCP-Server' }; await writeFile( join(testDir, 'package.json'), JSON.stringify(packageJson, null, 2), 'utf-8' ); await writeFile( join(testDir, 'server.json'), JSON.stringify(serverJson, null, 2), 'utf-8' ); } /** * Simulates MCP Registry API response structure. * @param serverName - The server name to look up. * @returns Simulated API response. */ function simulateRegistryApiResponse(serverName: string): any { return { name: serverName, description: 'MCP server for Financial Modeling Prep API with 250+ financial data tools', version: '2.5.0', status: 'active', packages: [ { registry_type: 'npm', registry_base_url: 'https://registry.npmjs.org', identifier: 'financial-modeling-prep-mcp-server', version: '2.5.0', runtime_hint: 'npx', transport: { type: 'streamable-http', url: 'https://financial-modeling-prep-mcp-server-production.up.railway.app/mcp' } } ], repository: { url: 'https://github.com/imbenrabi/Financial-Modeling-Prep-MCP-Server', source: 'github' }, website_url: 'https://github.com/imbenrabi/Financial-Modeling-Prep-MCP-Server', created_at: '2024-01-01T00:00:00Z', updated_at: '2024-01-01T00:00:00Z' }; } /** * Simulates NPM Registry API response. * @param packageName - The package name to look up. * @returns Simulated NPM API response. */ function simulateNpmApiResponse(packageName: string): any { return { name: packageName, version: '2.5.0', mcpName: 'io.github.imbenrabi/financial-modeling-prep-mcp-server', description: 'MCP server for Financial Modeling Prep API', main: 'dist/index.js', bin: { 'fmp-mcp': 'dist/index.js' }, repository: { type: 'git', url: 'https://github.com/imbenrabi/Financial-Modeling-Prep-MCP-Server' }, keywords: ['mcp', 'financial', 'api'], license: 'Apache-2.0', author: 'imbenrabi', dist: { tarball: `https://registry.npmjs.org/${packageName}/-/${packageName}-2.5.0.tgz`, shasum: 'abc123def456', integrity: 'sha512-...' } }; } describe('Registry API Response Validation', () => { beforeEach(async () => { await createTestFiles(); }); it('should validate registry API response structure', async () => { const serverJson = JSON.parse(await readFile(join(testDir, 'server.json'), 'utf-8')); const apiResponse = simulateRegistryApiResponse(serverJson.name); // Validate required fields in API response expect(apiResponse.name).toBe(serverJson.name); expect(apiResponse.description).toBe(serverJson.description); expect(apiResponse.version).toBe(serverJson.version); expect(apiResponse.status).toBe('active'); expect(apiResponse.packages).toBeDefined(); expect(Array.isArray(apiResponse.packages)).toBe(true); }); it('should validate package information in registry response', async () => { const serverJson = JSON.parse(await readFile(join(testDir, 'server.json'), 'utf-8')); const apiResponse = simulateRegistryApiResponse(serverJson.name); const npmPackage = apiResponse.packages.find((pkg: any) => pkg.registry_type === 'npm'); expect(npmPackage).toBeDefined(); expect(npmPackage.identifier).toBe('financial-modeling-prep-mcp-server'); expect(npmPackage.version).toBe('2.5.0'); expect(npmPackage.runtime_hint).toBe('npx'); }); it('should validate repository information in registry response', async () => { const serverJson = JSON.parse(await readFile(join(testDir, 'server.json'), 'utf-8')); const apiResponse = simulateRegistryApiResponse(serverJson.name); expect(apiResponse.repository).toBeDefined(); expect(apiResponse.repository.url).toBe(serverJson.repository.url); expect(apiResponse.repository.source).toBe('github'); }); it('should validate timestamps in registry response', async () => { const serverJson = JSON.parse(await readFile(join(testDir, 'server.json'), 'utf-8')); const apiResponse = simulateRegistryApiResponse(serverJson.name); expect(apiResponse.created_at).toBeDefined(); expect(apiResponse.updated_at).toBeDefined(); expect(new Date(apiResponse.created_at)).toBeInstanceOf(Date); expect(new Date(apiResponse.updated_at)).toBeInstanceOf(Date); }); }); describe('Server Discovery Functionality', () => { beforeEach(async () => { await createTestFiles(); }); it('should validate server can be discovered by name', async () => { const serverJson = JSON.parse(await readFile(join(testDir, 'server.json'), 'utf-8')); const searchResults = [ simulateRegistryApiResponse(serverJson.name) ]; const foundServer = searchResults.find(server => server.name === serverJson.name); expect(foundServer).toBeDefined(); expect(foundServer.name).toBe('io.github.imbenrabi/financial-modeling-prep-mcp-server'); }); it('should validate server can be discovered by keywords', async () => { const packageJson = JSON.parse(await readFile(join(testDir, 'package.json'), 'utf-8')); // Simulate search by keywords const searchKeywords = ['financial', 'mcp', 'api']; const serverKeywords = ['financial', 'modeling', 'prep', 'mcp', 'api', 'data']; const hasMatchingKeywords = searchKeywords.some(keyword => serverKeywords.includes(keyword) ); expect(hasMatchingKeywords).toBe(true); }); it('should validate server can be discovered by description', async () => { const serverJson = JSON.parse(await readFile(join(testDir, 'server.json'), 'utf-8')); // Simulate search by description content const searchTerms = ['financial', 'modeling', 'prep', 'tools']; const description = serverJson.description.toLowerCase(); const hasMatchingTerms = searchTerms.some(term => description.includes(term.toLowerCase()) ); expect(hasMatchingTerms).toBe(true); }); it('should validate server discovery returns installation instructions', async () => { const serverJson = JSON.parse(await readFile(join(testDir, 'server.json'), 'utf-8')); const apiResponse = simulateRegistryApiResponse(serverJson.name); const npmPackage = apiResponse.packages.find((pkg: any) => pkg.registry_type === 'npm'); // Validate installation methods can be derived const installationMethods = { npm: `npm install ${npmPackage.identifier}`, npx: `npx ${npmPackage.identifier}`, global: `npm install -g ${npmPackage.identifier}` }; expect(installationMethods.npm).toContain('financial-modeling-prep-mcp-server'); expect(installationMethods.npx).toContain('financial-modeling-prep-mcp-server'); expect(installationMethods.global).toContain('financial-modeling-prep-mcp-server'); }); }); describe('NPM Registry Integration', () => { beforeEach(async () => { await createTestFiles(); }); it('should validate NPM registry response structure', async () => { const packageJson = JSON.parse(await readFile(join(testDir, 'package.json'), 'utf-8')); const npmResponse = simulateNpmApiResponse(packageJson.name); expect(npmResponse.name).toBe(packageJson.name); expect(npmResponse.version).toBe(packageJson.version); expect(npmResponse.mcpName).toBe(packageJson.mcpName); expect(npmResponse.description).toBeDefined(); }); it('should validate NPM package has required MCP fields', async () => { const packageJson = JSON.parse(await readFile(join(testDir, 'package.json'), 'utf-8')); const npmResponse = simulateNpmApiResponse(packageJson.name); expect(npmResponse.mcpName).toBeDefined(); expect(npmResponse.mcpName).toBe('io.github.imbenrabi/financial-modeling-prep-mcp-server'); expect(npmResponse.bin).toBeDefined(); expect(npmResponse.bin['fmp-mcp']).toBeDefined(); }); it('should validate NPM package distribution information', async () => { const packageJson = JSON.parse(await readFile(join(testDir, 'package.json'), 'utf-8')); const npmResponse = simulateNpmApiResponse(packageJson.name); expect(npmResponse.dist).toBeDefined(); expect(npmResponse.dist.tarball).toContain(packageJson.name); expect(npmResponse.dist.shasum).toBeDefined(); expect(npmResponse.dist.integrity).toBeDefined(); }); it('should validate cross-registry consistency', async () => { const packageJson = JSON.parse(await readFile(join(testDir, 'package.json'), 'utf-8')); const serverJson = JSON.parse(await readFile(join(testDir, 'server.json'), 'utf-8')); const npmResponse = simulateNpmApiResponse(packageJson.name); const registryResponse = simulateRegistryApiResponse(serverJson.name); // Validate consistency between NPM and MCP registry expect(npmResponse.mcpName).toBe(registryResponse.name); expect(npmResponse.version).toBe(registryResponse.version); const npmPackageInRegistry = registryResponse.packages.find( (pkg: any) => pkg.registry_type === 'npm' ); expect(npmPackageInRegistry.identifier).toBe(npmResponse.name); expect(npmPackageInRegistry.version).toBe(npmResponse.version); }); }); describe('Transport Configuration Validation', () => { beforeEach(async () => { await createTestFiles(); }); it('should validate HTTP transport configuration', async () => { const serverJson = JSON.parse(await readFile(join(testDir, 'server.json'), 'utf-8')); const npmPackage = serverJson.packages.find((pkg: any) => pkg.registry_type === 'npm'); expect(npmPackage.transport).toBeDefined(); expect(npmPackage.transport.type).toBe('streamable-http'); expect(npmPackage.transport.url).toBeDefined(); expect(npmPackage.transport.url).toMatch(/^https?:\/\//); }); it('should validate transport URL accessibility format', async () => { const serverJson = JSON.parse(await readFile(join(testDir, 'server.json'), 'utf-8')); const npmPackage = serverJson.packages.find((pkg: any) => pkg.registry_type === 'npm'); const transportUrl = npmPackage.transport.url; // Validate URL format expect(() => new URL(transportUrl)).not.toThrow(); expect(transportUrl).toMatch(/^https:\/\//); // Should use HTTPS expect(transportUrl).toContain('/mcp'); // Should have MCP endpoint }); it('should validate stdio transport as alternative', async () => { // Create server.json with stdio transport const serverJsonWithStdio = { name: 'io.github.imbenrabi/financial-modeling-prep-mcp-server', version: '2.5.0', description: 'Test server', packages: [ { registry_type: 'npm', identifier: 'financial-modeling-prep-mcp-server', version: '2.5.0', runtime_hint: 'npx', transport: { type: 'stdio' } } ] }; await writeFile( join(testDir, 'server-stdio.json'), JSON.stringify(serverJsonWithStdio, null, 2), 'utf-8' ); const serverJson = JSON.parse(await readFile(join(testDir, 'server-stdio.json'), 'utf-8')); const npmPackage = serverJson.packages.find((pkg: any) => pkg.registry_type === 'npm'); expect(npmPackage.transport.type).toBe('stdio'); expect(npmPackage.transport.url).toBeUndefined(); // stdio doesn't need URL }); it('should validate runtime arguments configuration', async () => { const serverJson = JSON.parse(await readFile(join(testDir, 'server.json'), 'utf-8')); // Add runtime arguments to test const serverJsonWithArgs = { ...serverJson, packages: [ { ...serverJson.packages[0], package_arguments: [ { type: 'named', name: '--fmp-token', description: 'Financial Modeling Prep API access token', is_required: false, format: 'string' }, { type: 'named', name: '--port', description: 'Port number for HTTP server mode', is_required: false, format: 'number' } ] } ] }; await writeFile( join(testDir, 'server-with-args.json'), JSON.stringify(serverJsonWithArgs, null, 2), 'utf-8' ); const testServerJson = JSON.parse(await readFile(join(testDir, 'server-with-args.json'), 'utf-8')); const npmPackage = testServerJson.packages.find((pkg: any) => pkg.registry_type === 'npm'); expect(npmPackage.package_arguments).toBeDefined(); expect(Array.isArray(npmPackage.package_arguments)).toBe(true); expect(npmPackage.package_arguments.length).toBeGreaterThan(0); const tokenArg = npmPackage.package_arguments.find((arg: any) => arg.name === '--fmp-token'); expect(tokenArg).toBeDefined(); expect(tokenArg.type).toBe('named'); expect(tokenArg.format).toBe('string'); }); }); describe('Registry Search and Filtering', () => { it('should validate server appears in category searches', async () => { await createTestFiles(); const serverJson = JSON.parse(await readFile(join(testDir, 'server.json'), 'utf-8')); // Simulate category-based search results const financialServers = [ simulateRegistryApiResponse(serverJson.name) ]; const foundInFinancial = financialServers.some(server => server.description.toLowerCase().includes('financial') ); expect(foundInFinancial).toBe(true); }); it('should validate server metadata supports filtering', async () => { await createTestFiles(); const serverJson = JSON.parse(await readFile(join(testDir, 'server.json'), 'utf-8')); const apiResponse = simulateRegistryApiResponse(serverJson.name); // Validate filterable attributes const filterableAttributes = { status: apiResponse.status, registryType: apiResponse.packages[0].registry_type, transportType: apiResponse.packages[0].transport?.type || 'none', hasRepository: !!apiResponse.repository, hasWebsite: !!apiResponse.website_url }; expect(filterableAttributes.status).toBe('active'); expect(filterableAttributes.registryType).toBe('npm'); expect(filterableAttributes.transportType).toBeDefined(); expect(filterableAttributes.transportType).not.toBe('none'); expect(filterableAttributes.hasRepository).toBe(true); expect(filterableAttributes.hasWebsite).toBe(true); }); it('should validate server supports version-based queries', async () => { await createTestFiles(); const serverJson = JSON.parse(await readFile(join(testDir, 'server.json'), 'utf-8')); const apiResponse = simulateRegistryApiResponse(serverJson.name); // Validate version information is accessible expect(apiResponse.version).toBeDefined(); expect(apiResponse.version).toMatch(/^\d+\.\d+\.\d+/); const npmPackage = apiResponse.packages.find((pkg: any) => pkg.registry_type === 'npm'); expect(npmPackage.version).toBe(apiResponse.version); }); }); });

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