import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js' import { beforeEach, describe, expect, it, vi } from 'vitest' import { registerSchemaTools } from '../../../src/tools/schema.js' import { callTool, connectClient, type FakeManager, fakeManager } from '../helpers.js' describe('schema tools', () => { let driver: { listDatabases: ReturnType listTables: ReturnType describeTable: ReturnType } let manager: FakeManager let client: Awaited> beforeEach(async () => { driver = { listDatabases: vi.fn(async () => [{ name: 'app', sizeBytes: 1024 }]), listTables: vi.fn(async () => [{ schema: 'public', name: 'users', rowEstimate: 5 }]), describeTable: vi.fn(async () => ({ columns: [{ name: 'id', type: 'integer', nullable: false, default: null }], primaryKey: ['id'], indexes: [], foreignKeys: [] })) } manager = fakeManager() manager.get.mockImplementation(async () => ({ driver, config: { name: 'c', type: 'postgres', host: 'h', user: 'u', readonly: false }, source: 'store' })) const server = new McpServer({ name: 'test', version: '0.0.0' }) registerSchemaTools(server, manager) client = await connectClient(server) }) it('list_databases returns database info', async () => { const response = await callTool(client, 'list_databases', { connection: 'c' }) expect(response.isError).toBe(false) expect(response.json()).toEqual([{ name: 'app', sizeBytes: 1024 }]) }) it('list_tables forwards database and schema filters', async () => { const response = await callTool(client, 'list_tables', { connection: 'c', database: 'db', schema: 'public' }) expect(response.isError).toBe(false) expect(driver.listTables).toHaveBeenCalledWith({ database: 'db', schema: 'public' }) expect(response.json()).toEqual([{ schema: 'public', name: 'users', rowEstimate: 5 }]) }) it('describe_table forwards args and returns the description', async () => { const response = await callTool(client, 'describe_table', { connection: 'c', table: 'users' }) expect(response.isError).toBe(false) expect(driver.describeTable).toHaveBeenCalledWith({ table: 'users', database: undefined, schema: undefined }) expect((response.json() as { primaryKey: string[] }).primaryKey).toEqual(['id']) }) it('formats driver errors', async () => { driver.describeTable.mockRejectedValue(new Error("table 'public.ghost' not found")) const response = await callTool(client, 'describe_table', { connection: 'c', table: 'ghost' }) expect(response.isError).toBe(true) expect(response.text).toContain('not found') }) it('reports manager errors per tool', async () => { manager.get.mockRejectedValue(new Error('no such connection')) for (const [tool, args] of [ ['list_databases', { connection: 'x' }], ['list_tables', { connection: 'x' }], ['describe_table', { connection: 'x', table: 't' }] ] as const) { const response = await callTool(client, tool, args as Record) expect(response.isError).toBe(true) expect(response.text).toContain('no such connection') } }) })