@boundless-oss/atlas
Version:
Atlas - MCP Server for comprehensive startup project management
162 lines (139 loc) • 6.1 kB
text/typescript
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { AtlasServer } from '../server.js';
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js';
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
// Mock the dashboard server module to prevent database initialization
vi.mock('../web-dashboard/server.js', () => ({
DashboardServer: vi.fn().mockImplementation(() => ({
start: vi.fn().mockResolvedValue(undefined),
stop: vi.fn().mockResolvedValue(undefined),
getUrl: vi.fn().mockReturnValue('http://localhost:3001'),
isHealthy: vi.fn().mockReturnValue(true),
getConfig: vi.fn().mockReturnValue({
enabled: false,
port: 3001,
host: 'localhost'
})
}))
}));
// Mock the SQLite manager to prevent database initialization
vi.mock('../storage/sqlite-manager.js', () => ({
getSQLiteManager: vi.fn(() => ({
initialize: vi.fn().mockResolvedValue(true),
close: vi.fn().mockResolvedValue(true),
query: vi.fn().mockResolvedValue({ success: true, data: [] }),
get: vi.fn().mockResolvedValue({ success: true, data: null }),
run: vi.fn().mockResolvedValue({ success: true, data: { changes: 1 } })
})),
ensureDatabaseReady: vi.fn().mockResolvedValue({
getConnectionInfo: () => ({
isInitialized: true,
dbPath: ':memory:'
})
}),
SQLiteManager: vi.fn()
}));
// Mock data migration
vi.mock('../storage/data-migration.js', () => ({
autoMigrateOnStartup: vi.fn().mockResolvedValue(undefined)
}));
describe('AtlasServer', () => {
let server: AtlasServer;
let client: Client;
let serverTransport: InMemoryTransport;
let clientTransport: InMemoryTransport;
beforeEach(async () => {
// Set NODE_ENV to test to ensure test configuration is used
process.env.NODE_ENV = 'test';
process.env.ATLAS_DASHBOARD_ENABLED = 'false'; // Disable dashboard in tests
server = new AtlasServer();
// Initialize server (this will register modules)
await (server as any).initialize();
// Create in-memory transports for testing
const transports = InMemoryTransport.createLinkedPair();
serverTransport = transports[0];
clientTransport = transports[1];
// Connect server with in-memory transport instead of stdio
const serverReady = (server as any).server.connect(serverTransport);
// Connect client
client = new Client({
name: 'test-client',
version: '1.0.0',
}, {
capabilities: {},
});
const clientReady = client.connect(clientTransport);
// Wait for both to be ready
await Promise.all([serverReady, clientReady]);
});
afterEach(async () => {
await client.close();
await (server as any).server.close();
});
describe('Initialization', () => {
it('should create server with correct name and version', async () => {
// Check that the server was created
expect(server).toBeDefined();
expect((server as any).server).toBeDefined();
});
it('should register required capabilities', async () => {
// Capabilities are registered when modules are loaded
expect((server as any).server).toBeDefined();
// The actual capability check would be done through client requests
});
});
describe('Tool Registration', () => {
it('should register core tools', async () => {
const response = await client.listTools();
expect(response.tools).toBeDefined();
expect(response.tools.length).toBeGreaterThan(0);
// Check for specific tools from migrated modules
const toolNames = response.tools.map((t: any) => t.name);
// Tools are namespaced with module names
expect(toolNames).toContain('kanban--create_kanban_board');
expect(toolNames).toContain('kanban--create_kanban_task');
expect(toolNames).toContain('workspace--create_workspace');
expect(toolNames).toContain('development--create_feature');
expect(toolNames).toContain('agile-management--create_user_story');
});
});
describe('Resource Registration', () => {
it('should register core resources', async () => {
const response = await client.listResources();
expect(response.resources).toBeDefined();
expect(response.resources.length).toBeGreaterThan(0);
// Check for specific resources
const resourceUris = response.resources.map((r: any) => r.uri);
expect(resourceUris).toContain('atlas://dashboard');
expect(resourceUris).toContain('atlas://database/stats');
expect(resourceUris).toContain('atlas://tools/manifest');
});
});
describe('Prompt Registration', () => {
it('should not register prompts in this architecture', async () => {
// The 12-factor architecture doesn't use prompts
// This is handled by the tool-based approach instead
expect(true).toBe(true);
});
});
describe('Module Integration', () => {
it('should integrate kanban module tools', async () => {
const response = await client.listTools();
// Check for kanban-specific tools
const toolNames = response.tools.map((t: any) => t.name);
expect(toolNames).toContain('kanban--create_kanban_board');
expect(toolNames).toContain('kanban--move_kanban_task');
});
it('should integrate development module tools', async () => {
const response = await client.listTools();
// Check for development-specific tools
const toolNames = response.tools.map((t: any) => t.name);
expect(toolNames).toContain('development--create_feature'); // from development module
expect(toolNames).toContain('developer-workflow--start_feature'); // from developer-workflow module
expect(toolNames).toContain('development--write_test'); // from development module
expect(toolNames).toContain('development--run_tests'); // from development module
expect(toolNames).toContain('development--enforce_tdd'); // from development module
});
});
});