import { describe, it, expect } from 'vitest'; import { generateMcpConfig } from '../src/services/mcp-config-generator.js'; import type { McpServer } from '@prisma/client'; function makeServer(overrides: Partial = {}): McpServer { return { id: 's1', name: 'slack', description: 'Slack MCP', packageName: '@anthropic/slack-mcp', dockerImage: null, transport: 'STDIO', repositoryUrl: null, externalUrl: null, command: null, containerPort: null, replicas: 1, env: [], healthCheck: null, version: 1, createdAt: new Date(), updatedAt: new Date(), templateName: null, templateVersion: null, ...overrides, }; } describe('generateMcpConfig', () => { it('returns empty mcpServers for empty input', () => { const result = generateMcpConfig([]); expect(result).toEqual({ mcpServers: {} }); }); it('generates config for a single STDIO server', () => { const result = generateMcpConfig([ { server: makeServer(), resolvedEnv: {} }, ]); expect(result.mcpServers['slack']).toBeDefined(); expect(result.mcpServers['slack']?.command).toBe('npx'); expect(result.mcpServers['slack']?.args).toEqual(['-y', '@anthropic/slack-mcp']); }); it('includes resolved env when present for STDIO server', () => { const result = generateMcpConfig([ { server: makeServer(), resolvedEnv: { SLACK_TEAM_ID: 'T123' } }, ]); const config = result.mcpServers['slack']; expect(config?.env).toBeDefined(); expect(config?.env?.['SLACK_TEAM_ID']).toBe('T123'); }); it('omits env when resolvedEnv is empty', () => { const result = generateMcpConfig([ { server: makeServer(), resolvedEnv: {} }, ]); expect(result.mcpServers['slack']?.env).toBeUndefined(); }); it('generates multiple server configs', () => { const result = generateMcpConfig([ { server: makeServer({ name: 'slack' }), resolvedEnv: {} }, { server: makeServer({ name: 'github', id: 's2', packageName: '@anthropic/github-mcp' }), resolvedEnv: {} }, ]); expect(Object.keys(result.mcpServers)).toHaveLength(2); expect(result.mcpServers['slack']).toBeDefined(); expect(result.mcpServers['github']).toBeDefined(); }); it('uses server name as fallback when packageName is null', () => { const server = makeServer({ packageName: null }); const result = generateMcpConfig([ { server, resolvedEnv: {} }, ]); expect(result.mcpServers['slack']?.args).toEqual(['-y', 'slack']); }); it('generates URL-based config for SSE servers', () => { const server = makeServer({ name: 'sse-server', transport: 'SSE' }); const result = generateMcpConfig([ { server, resolvedEnv: { TOKEN: 'abc' } }, ]); const config = result.mcpServers['sse-server']; expect(config?.url).toBe('http://localhost:3100/api/v1/mcp/proxy/sse-server'); expect(config?.command).toBeUndefined(); expect(config?.args).toBeUndefined(); expect(config?.env).toBeUndefined(); }); it('generates URL-based config for STREAMABLE_HTTP servers', () => { const server = makeServer({ name: 'stream-server', transport: 'STREAMABLE_HTTP' }); const result = generateMcpConfig([ { server, resolvedEnv: {} }, ]); const config = result.mcpServers['stream-server']; expect(config?.url).toBe('http://localhost:3100/api/v1/mcp/proxy/stream-server'); expect(config?.command).toBeUndefined(); }); it('mixes STDIO and SSE servers correctly', () => { const result = generateMcpConfig([ { server: makeServer({ name: 'stdio-srv', transport: 'STDIO' }), resolvedEnv: {} }, { server: makeServer({ name: 'sse-srv', transport: 'SSE' }), resolvedEnv: {} }, ]); expect(result.mcpServers['stdio-srv']?.command).toBe('npx'); expect(result.mcpServers['sse-srv']?.url).toBeDefined(); }); });