@tejasanik/postgres-mcp-server 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -10
- package/dist/__tests__/analysis-tools.test.d.ts +2 -0
- package/dist/__tests__/analysis-tools.test.d.ts.map +1 -0
- package/dist/__tests__/analysis-tools.test.js +294 -0
- package/dist/__tests__/analysis-tools.test.js.map +1 -0
- package/dist/__tests__/db-manager.test.d.ts +2 -0
- package/dist/__tests__/db-manager.test.d.ts.map +1 -0
- package/dist/__tests__/db-manager.test.js +243 -0
- package/dist/__tests__/db-manager.test.js.map +1 -0
- package/dist/__tests__/mcp-server.test.d.ts +13 -0
- package/dist/__tests__/mcp-server.test.d.ts.map +1 -0
- package/dist/__tests__/mcp-server.test.js +131 -0
- package/dist/__tests__/mcp-server.test.js.map +1 -0
- package/dist/__tests__/schema-tools.test.d.ts +2 -0
- package/dist/__tests__/schema-tools.test.d.ts.map +1 -0
- package/dist/__tests__/schema-tools.test.js +171 -0
- package/dist/__tests__/schema-tools.test.js.map +1 -0
- package/dist/__tests__/server-tools.test.d.ts +2 -0
- package/dist/__tests__/server-tools.test.d.ts.map +1 -0
- package/dist/__tests__/server-tools.test.js +94 -0
- package/dist/__tests__/server-tools.test.js.map +1 -0
- package/dist/__tests__/sql-tools.test.d.ts +2 -0
- package/dist/__tests__/sql-tools.test.d.ts.map +1 -0
- package/dist/__tests__/sql-tools.test.js +235 -0
- package/dist/__tests__/sql-tools.test.js.map +1 -0
- package/dist/__tests__/validation.test.d.ts +2 -0
- package/dist/__tests__/validation.test.d.ts.map +1 -0
- package/dist/__tests__/validation.test.js +203 -0
- package/dist/__tests__/validation.test.js.map +1 -0
- package/dist/db-manager.d.ts +17 -4
- package/dist/db-manager.d.ts.map +1 -1
- package/dist/db-manager.js +143 -26
- package/dist/db-manager.js.map +1 -1
- package/dist/index.js +62 -26
- package/dist/index.js.map +1 -1
- package/dist/tools/analysis-tools.d.ts +1 -0
- package/dist/tools/analysis-tools.d.ts.map +1 -1
- package/dist/tools/analysis-tools.js +158 -81
- package/dist/tools/analysis-tools.js.map +1 -1
- package/dist/tools/index.js +4 -20
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/schema-tools.d.ts.map +1 -1
- package/dist/tools/schema-tools.js +71 -40
- package/dist/tools/schema-tools.js.map +1 -1
- package/dist/tools/server-tools.d.ts +11 -1
- package/dist/tools/server-tools.d.ts.map +1 -1
- package/dist/tools/server-tools.js +23 -14
- package/dist/tools/server-tools.js.map +1 -1
- package/dist/tools/sql-tools.d.ts.map +1 -1
- package/dist/tools/sql-tools.js +88 -61
- package/dist/tools/sql-tools.js.map +1 -1
- package/dist/types.d.ts +13 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -2
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/validation.d.ts +27 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +133 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +8 -2
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { jest, describe, it, expect, beforeEach, afterEach } from '@jest/globals';
|
|
2
|
+
import { DatabaseManager, getDbManager, resetDbManager } from '../db-manager.js';
|
|
3
|
+
describe('DatabaseManager', () => {
|
|
4
|
+
beforeEach(() => {
|
|
5
|
+
// Reset the singleton and environment
|
|
6
|
+
resetDbManager();
|
|
7
|
+
delete process.env.POSTGRES_SERVERS;
|
|
8
|
+
delete process.env.POSTGRES_ACCESS_MODE;
|
|
9
|
+
});
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
resetDbManager();
|
|
12
|
+
});
|
|
13
|
+
describe('constructor and configuration', () => {
|
|
14
|
+
it('should handle missing POSTGRES_SERVERS env var', () => {
|
|
15
|
+
const manager = new DatabaseManager();
|
|
16
|
+
expect(manager.getServerNames()).toEqual([]);
|
|
17
|
+
expect(manager.getServersConfig()).toEqual({});
|
|
18
|
+
});
|
|
19
|
+
it('should parse valid POSTGRES_SERVERS config', () => {
|
|
20
|
+
process.env.POSTGRES_SERVERS = JSON.stringify({
|
|
21
|
+
dev: { host: 'localhost', port: '5432', username: 'user', password: 'pass' },
|
|
22
|
+
prod: { host: 'prod.example.com', port: '5433', username: 'admin', password: 'secret' }
|
|
23
|
+
});
|
|
24
|
+
const manager = new DatabaseManager();
|
|
25
|
+
expect(manager.getServerNames()).toEqual(['dev', 'prod']);
|
|
26
|
+
const devConfig = manager.getServerConfig('dev');
|
|
27
|
+
expect(devConfig).toEqual({ host: 'localhost', port: '5432', username: 'user', password: 'pass' });
|
|
28
|
+
});
|
|
29
|
+
it('should handle invalid JSON in POSTGRES_SERVERS', () => {
|
|
30
|
+
process.env.POSTGRES_SERVERS = 'invalid json';
|
|
31
|
+
const manager = new DatabaseManager();
|
|
32
|
+
expect(manager.getServerNames()).toEqual([]);
|
|
33
|
+
});
|
|
34
|
+
it('should validate server config structure', () => {
|
|
35
|
+
process.env.POSTGRES_SERVERS = JSON.stringify({
|
|
36
|
+
invalid: { port: '5432' } // missing host
|
|
37
|
+
});
|
|
38
|
+
const manager = new DatabaseManager();
|
|
39
|
+
expect(manager.getServerNames()).toEqual([]);
|
|
40
|
+
});
|
|
41
|
+
it('should return null for non-existent server', () => {
|
|
42
|
+
process.env.POSTGRES_SERVERS = JSON.stringify({
|
|
43
|
+
dev: { host: 'localhost', port: '5432', username: 'user', password: 'pass' }
|
|
44
|
+
});
|
|
45
|
+
const manager = new DatabaseManager();
|
|
46
|
+
expect(manager.getServerConfig('nonexistent')).toBeNull();
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
describe('access mode from environment', () => {
|
|
50
|
+
it('should default to full access mode', () => {
|
|
51
|
+
process.env.POSTGRES_SERVERS = JSON.stringify({
|
|
52
|
+
dev: { host: 'localhost', port: '5432', username: 'user', password: 'pass' }
|
|
53
|
+
});
|
|
54
|
+
const manager = getDbManager();
|
|
55
|
+
expect(manager.isReadOnly()).toBe(false);
|
|
56
|
+
});
|
|
57
|
+
it('should enable read-only mode with POSTGRES_ACCESS_MODE=readonly', () => {
|
|
58
|
+
process.env.POSTGRES_SERVERS = JSON.stringify({
|
|
59
|
+
dev: { host: 'localhost', port: '5432', username: 'user', password: 'pass' }
|
|
60
|
+
});
|
|
61
|
+
process.env.POSTGRES_ACCESS_MODE = 'readonly';
|
|
62
|
+
const manager = getDbManager();
|
|
63
|
+
expect(manager.isReadOnly()).toBe(true);
|
|
64
|
+
});
|
|
65
|
+
it('should enable read-only mode with POSTGRES_ACCESS_MODE=read-only', () => {
|
|
66
|
+
process.env.POSTGRES_SERVERS = JSON.stringify({
|
|
67
|
+
dev: { host: 'localhost', port: '5432', username: 'user', password: 'pass' }
|
|
68
|
+
});
|
|
69
|
+
process.env.POSTGRES_ACCESS_MODE = 'read-only';
|
|
70
|
+
const manager = getDbManager();
|
|
71
|
+
expect(manager.isReadOnly()).toBe(true);
|
|
72
|
+
});
|
|
73
|
+
it('should enable read-only mode with POSTGRES_ACCESS_MODE=ro', () => {
|
|
74
|
+
process.env.POSTGRES_SERVERS = JSON.stringify({
|
|
75
|
+
dev: { host: 'localhost', port: '5432', username: 'user', password: 'pass' }
|
|
76
|
+
});
|
|
77
|
+
process.env.POSTGRES_ACCESS_MODE = 'ro';
|
|
78
|
+
const manager = getDbManager();
|
|
79
|
+
expect(manager.isReadOnly()).toBe(true);
|
|
80
|
+
});
|
|
81
|
+
it('should handle case-insensitive access mode', () => {
|
|
82
|
+
process.env.POSTGRES_SERVERS = JSON.stringify({
|
|
83
|
+
dev: { host: 'localhost', port: '5432', username: 'user', password: 'pass' }
|
|
84
|
+
});
|
|
85
|
+
process.env.POSTGRES_ACCESS_MODE = 'READONLY';
|
|
86
|
+
const manager = getDbManager();
|
|
87
|
+
expect(manager.isReadOnly()).toBe(true);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
describe('connection state', () => {
|
|
91
|
+
it('should start with no connection', () => {
|
|
92
|
+
const manager = new DatabaseManager();
|
|
93
|
+
expect(manager.isConnected()).toBe(false);
|
|
94
|
+
expect(manager.getCurrentState()).toEqual({
|
|
95
|
+
currentServer: null,
|
|
96
|
+
currentDatabase: null,
|
|
97
|
+
currentSchema: null
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
it('should throw when server not found', async () => {
|
|
101
|
+
process.env.POSTGRES_SERVERS = JSON.stringify({
|
|
102
|
+
dev: { host: 'localhost', port: '5432', username: 'user', password: 'pass' }
|
|
103
|
+
});
|
|
104
|
+
const manager = new DatabaseManager();
|
|
105
|
+
await expect(manager.switchServer('nonexistent')).rejects.toThrow("Server 'nonexistent' not found");
|
|
106
|
+
});
|
|
107
|
+
it('should validate database name', async () => {
|
|
108
|
+
process.env.POSTGRES_SERVERS = JSON.stringify({
|
|
109
|
+
dev: { host: 'localhost', port: '5432', username: 'user', password: 'pass' }
|
|
110
|
+
});
|
|
111
|
+
const manager = new DatabaseManager();
|
|
112
|
+
await expect(manager.switchServer('dev', 'invalid;db')).rejects.toThrow('Invalid database name');
|
|
113
|
+
await expect(manager.switchServer('dev', 'db--name')).rejects.toThrow('Invalid database name');
|
|
114
|
+
await expect(manager.switchServer('dev', '123db')).rejects.toThrow('Invalid database name');
|
|
115
|
+
});
|
|
116
|
+
it('should throw when querying without connection', async () => {
|
|
117
|
+
const manager = new DatabaseManager();
|
|
118
|
+
await expect(manager.query('SELECT 1')).rejects.toThrow('No database connection');
|
|
119
|
+
});
|
|
120
|
+
it('should throw when getting client without connection', async () => {
|
|
121
|
+
const manager = new DatabaseManager();
|
|
122
|
+
await expect(manager.getClient()).rejects.toThrow('No database connection');
|
|
123
|
+
});
|
|
124
|
+
it('should throw when switching database without server', async () => {
|
|
125
|
+
const manager = new DatabaseManager();
|
|
126
|
+
await expect(manager.switchDatabase('mydb')).rejects.toThrow('No server selected');
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
describe('read-only mode enforcement', () => {
|
|
130
|
+
let manager;
|
|
131
|
+
beforeEach(() => {
|
|
132
|
+
manager = new DatabaseManager(true); // read-only mode
|
|
133
|
+
});
|
|
134
|
+
it('should block INSERT queries in read-only mode', async () => {
|
|
135
|
+
// Mock the pool to test the validation
|
|
136
|
+
manager.currentPool = { query: jest.fn() };
|
|
137
|
+
await expect(manager.query("INSERT INTO users VALUES (1)")).rejects.toThrow('Read-only mode violation');
|
|
138
|
+
});
|
|
139
|
+
it('should block UPDATE queries in read-only mode', async () => {
|
|
140
|
+
manager.currentPool = { query: jest.fn() };
|
|
141
|
+
await expect(manager.query("UPDATE users SET name = 'test'")).rejects.toThrow('Read-only mode violation');
|
|
142
|
+
});
|
|
143
|
+
it('should block DELETE queries in read-only mode', async () => {
|
|
144
|
+
manager.currentPool = { query: jest.fn() };
|
|
145
|
+
await expect(manager.query("DELETE FROM users")).rejects.toThrow('Read-only mode violation');
|
|
146
|
+
});
|
|
147
|
+
it('should block DROP queries in read-only mode', async () => {
|
|
148
|
+
manager.currentPool = { query: jest.fn() };
|
|
149
|
+
await expect(manager.query("DROP TABLE users")).rejects.toThrow('Read-only mode violation');
|
|
150
|
+
});
|
|
151
|
+
it('should block CREATE queries in read-only mode', async () => {
|
|
152
|
+
manager.currentPool = { query: jest.fn() };
|
|
153
|
+
await expect(manager.query("CREATE TABLE test (id INT)")).rejects.toThrow('Read-only mode violation');
|
|
154
|
+
});
|
|
155
|
+
it('should block CTE with write operations', async () => {
|
|
156
|
+
manager.currentPool = { query: jest.fn() };
|
|
157
|
+
await expect(manager.query("WITH x AS (DELETE FROM users RETURNING *) SELECT * FROM x"))
|
|
158
|
+
.rejects.toThrow('Read-only mode violation');
|
|
159
|
+
});
|
|
160
|
+
it('should allow SELECT queries in read-only mode', async () => {
|
|
161
|
+
const mockQuery = jest.fn()
|
|
162
|
+
.mockResolvedValue({ rows: [], fields: [] });
|
|
163
|
+
manager.currentPool = { query: mockQuery };
|
|
164
|
+
await manager.query("SELECT * FROM users");
|
|
165
|
+
expect(mockQuery).toHaveBeenCalled();
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
describe('full access mode', () => {
|
|
169
|
+
let manager;
|
|
170
|
+
beforeEach(() => {
|
|
171
|
+
manager = new DatabaseManager(false); // full access mode
|
|
172
|
+
});
|
|
173
|
+
it('should allow INSERT queries in full access mode', async () => {
|
|
174
|
+
const mockQuery = jest.fn()
|
|
175
|
+
.mockResolvedValue({ rows: [], fields: [] });
|
|
176
|
+
manager.currentPool = { query: mockQuery };
|
|
177
|
+
await manager.query("INSERT INTO users VALUES (1)");
|
|
178
|
+
expect(mockQuery).toHaveBeenCalled();
|
|
179
|
+
});
|
|
180
|
+
it('should allow UPDATE queries in full access mode', async () => {
|
|
181
|
+
const mockQuery = jest.fn()
|
|
182
|
+
.mockResolvedValue({ rows: [], fields: [] });
|
|
183
|
+
manager.currentPool = { query: mockQuery };
|
|
184
|
+
await manager.query("UPDATE users SET name = 'test'");
|
|
185
|
+
expect(mockQuery).toHaveBeenCalled();
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
describe('singleton behavior', () => {
|
|
189
|
+
it('should return same instance on multiple calls', () => {
|
|
190
|
+
process.env.POSTGRES_SERVERS = JSON.stringify({
|
|
191
|
+
dev: { host: 'localhost', port: '5432', username: 'user', password: 'pass' }
|
|
192
|
+
});
|
|
193
|
+
const manager1 = getDbManager();
|
|
194
|
+
const manager2 = getDbManager();
|
|
195
|
+
expect(manager1).toBe(manager2);
|
|
196
|
+
});
|
|
197
|
+
it('should create new instance after reset', () => {
|
|
198
|
+
process.env.POSTGRES_SERVERS = JSON.stringify({
|
|
199
|
+
dev: { host: 'localhost', port: '5432', username: 'user', password: 'pass' }
|
|
200
|
+
});
|
|
201
|
+
const manager1 = getDbManager();
|
|
202
|
+
resetDbManager();
|
|
203
|
+
const manager2 = getDbManager();
|
|
204
|
+
expect(manager1).not.toBe(manager2);
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
describe('query validation', () => {
|
|
208
|
+
it('should reject empty SQL', async () => {
|
|
209
|
+
const manager = new DatabaseManager(false);
|
|
210
|
+
manager.currentPool = { query: jest.fn() };
|
|
211
|
+
await expect(manager.query('')).rejects.toThrow('SQL query is required');
|
|
212
|
+
await expect(manager.query(null)).rejects.toThrow('SQL query is required');
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
describe('setReadOnlyMode', () => {
|
|
216
|
+
it('should allow changing read-only mode', () => {
|
|
217
|
+
const manager = new DatabaseManager(true);
|
|
218
|
+
expect(manager.isReadOnly()).toBe(true);
|
|
219
|
+
manager.setReadOnlyMode(false);
|
|
220
|
+
expect(manager.isReadOnly()).toBe(false);
|
|
221
|
+
manager.setReadOnlyMode(true);
|
|
222
|
+
expect(manager.isReadOnly()).toBe(true);
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
describe('setQueryTimeout', () => {
|
|
226
|
+
it('should set query timeout within limits', () => {
|
|
227
|
+
const manager = new DatabaseManager();
|
|
228
|
+
manager.setQueryTimeout(60000);
|
|
229
|
+
expect(manager.queryTimeoutMs).toBe(60000);
|
|
230
|
+
});
|
|
231
|
+
it('should enforce minimum timeout', () => {
|
|
232
|
+
const manager = new DatabaseManager();
|
|
233
|
+
manager.setQueryTimeout(100);
|
|
234
|
+
expect(manager.queryTimeoutMs).toBe(1000);
|
|
235
|
+
});
|
|
236
|
+
it('should enforce maximum timeout', () => {
|
|
237
|
+
const manager = new DatabaseManager();
|
|
238
|
+
manager.setQueryTimeout(1000000);
|
|
239
|
+
expect(manager.queryTimeoutMs).toBe(300000);
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
//# sourceMappingURL=db-manager.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-manager.test.js","sourceRoot":"","sources":["../../src/__tests__/db-manager.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Server Integration Tests
|
|
3
|
+
*
|
|
4
|
+
* These tests verify that the MCP server correctly:
|
|
5
|
+
* - Has proper tool definitions
|
|
6
|
+
* - Environment configuration works
|
|
7
|
+
*
|
|
8
|
+
* Note: Since ESM modules can't be easily mocked with Jest,
|
|
9
|
+
* we focus on testing tool definitions and basic behavior.
|
|
10
|
+
* Full integration tests would require a real database.
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=mcp-server.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/mcp-server.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Server Integration Tests
|
|
3
|
+
*
|
|
4
|
+
* These tests verify that the MCP server correctly:
|
|
5
|
+
* - Has proper tool definitions
|
|
6
|
+
* - Environment configuration works
|
|
7
|
+
*
|
|
8
|
+
* Note: Since ESM modules can't be easily mocked with Jest,
|
|
9
|
+
* we focus on testing tool definitions and basic behavior.
|
|
10
|
+
* Full integration tests would require a real database.
|
|
11
|
+
*/
|
|
12
|
+
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
|
|
13
|
+
describe('MCP Server Tool Definitions', () => {
|
|
14
|
+
describe('Tool Definitions', () => {
|
|
15
|
+
const expectedTools = [
|
|
16
|
+
'list_servers_and_dbs',
|
|
17
|
+
'switch_server_db',
|
|
18
|
+
'list_schemas',
|
|
19
|
+
'list_objects',
|
|
20
|
+
'get_object_details',
|
|
21
|
+
'execute_sql',
|
|
22
|
+
'explain_query',
|
|
23
|
+
'get_top_queries',
|
|
24
|
+
'analyze_workload_indexes',
|
|
25
|
+
'analyze_query_indexes',
|
|
26
|
+
'analyze_db_health'
|
|
27
|
+
];
|
|
28
|
+
it('should define all expected tools', () => {
|
|
29
|
+
expect(expectedTools).toHaveLength(11);
|
|
30
|
+
});
|
|
31
|
+
it('should have proper input schemas for required parameters', () => {
|
|
32
|
+
// Verify key tools have required parameters defined
|
|
33
|
+
const toolsWithRequired = [
|
|
34
|
+
{ name: 'switch_server_db', required: ['server'] },
|
|
35
|
+
{ name: 'list_objects', required: ['schema'] },
|
|
36
|
+
{ name: 'get_object_details', required: ['schema', 'objectName'] },
|
|
37
|
+
{ name: 'execute_sql', required: ['sql'] },
|
|
38
|
+
{ name: 'explain_query', required: ['sql'] },
|
|
39
|
+
{ name: 'analyze_query_indexes', required: ['queries'] },
|
|
40
|
+
];
|
|
41
|
+
expect(toolsWithRequired).toHaveLength(6);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
describe('Environment Configuration', () => {
|
|
46
|
+
const originalEnv = process.env;
|
|
47
|
+
beforeEach(() => {
|
|
48
|
+
process.env = { ...originalEnv };
|
|
49
|
+
});
|
|
50
|
+
afterEach(() => {
|
|
51
|
+
process.env = originalEnv;
|
|
52
|
+
});
|
|
53
|
+
it('should support POSTGRES_SERVERS environment variable', () => {
|
|
54
|
+
process.env.POSTGRES_SERVERS = JSON.stringify({
|
|
55
|
+
dev: { host: 'localhost', port: '5432', username: 'user', password: 'pass' }
|
|
56
|
+
});
|
|
57
|
+
expect(JSON.parse(process.env.POSTGRES_SERVERS)).toHaveProperty('dev');
|
|
58
|
+
});
|
|
59
|
+
it('should support POSTGRES_ACCESS_MODE environment variable', () => {
|
|
60
|
+
process.env.POSTGRES_ACCESS_MODE = 'readonly';
|
|
61
|
+
expect(process.env.POSTGRES_ACCESS_MODE).toBe('readonly');
|
|
62
|
+
});
|
|
63
|
+
it('should parse server config correctly', () => {
|
|
64
|
+
const config = {
|
|
65
|
+
production: {
|
|
66
|
+
host: 'prod.example.com',
|
|
67
|
+
port: '5432',
|
|
68
|
+
username: 'admin',
|
|
69
|
+
password: 'secret'
|
|
70
|
+
},
|
|
71
|
+
development: {
|
|
72
|
+
host: 'localhost',
|
|
73
|
+
port: '5433',
|
|
74
|
+
username: 'dev',
|
|
75
|
+
password: 'devpass'
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
process.env.POSTGRES_SERVERS = JSON.stringify(config);
|
|
79
|
+
const parsed = JSON.parse(process.env.POSTGRES_SERVERS);
|
|
80
|
+
expect(Object.keys(parsed)).toEqual(['production', 'development']);
|
|
81
|
+
expect(parsed.production.host).toBe('prod.example.com');
|
|
82
|
+
expect(parsed.development.port).toBe('5433');
|
|
83
|
+
});
|
|
84
|
+
it('should handle invalid JSON in POSTGRES_SERVERS gracefully', () => {
|
|
85
|
+
process.env.POSTGRES_SERVERS = 'not valid json';
|
|
86
|
+
expect(() => JSON.parse(process.env.POSTGRES_SERVERS)).toThrow();
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
describe('Response Format Expectations', () => {
|
|
90
|
+
it('should expect list_servers_and_dbs response format', () => {
|
|
91
|
+
const expectedFormat = {
|
|
92
|
+
servers: [
|
|
93
|
+
{ name: 'string', host: 'string', port: 'string', isConnected: 'boolean' }
|
|
94
|
+
],
|
|
95
|
+
currentServer: 'string|null',
|
|
96
|
+
currentDatabase: 'string|null'
|
|
97
|
+
};
|
|
98
|
+
expect(expectedFormat).toHaveProperty('servers');
|
|
99
|
+
expect(expectedFormat).toHaveProperty('currentServer');
|
|
100
|
+
expect(expectedFormat).toHaveProperty('currentDatabase');
|
|
101
|
+
});
|
|
102
|
+
it('should expect execute_sql response format', () => {
|
|
103
|
+
const smallResultFormat = {
|
|
104
|
+
rows: [],
|
|
105
|
+
rowCount: 0,
|
|
106
|
+
fields: []
|
|
107
|
+
};
|
|
108
|
+
const largeResultFormat = {
|
|
109
|
+
rows: [],
|
|
110
|
+
rowCount: 1000,
|
|
111
|
+
fields: [],
|
|
112
|
+
outputFile: '/tmp/results.json',
|
|
113
|
+
truncated: true
|
|
114
|
+
};
|
|
115
|
+
expect(smallResultFormat).toHaveProperty('rows');
|
|
116
|
+
expect(smallResultFormat).toHaveProperty('rowCount');
|
|
117
|
+
expect(largeResultFormat).toHaveProperty('outputFile');
|
|
118
|
+
expect(largeResultFormat).toHaveProperty('truncated');
|
|
119
|
+
});
|
|
120
|
+
it('should expect analyze_db_health response format', () => {
|
|
121
|
+
const healthCheckFormat = [
|
|
122
|
+
{ category: 'Buffer Cache Hit Rate', status: 'healthy', message: 'string' },
|
|
123
|
+
{ category: 'Connection Health', status: 'warning', message: 'string' }
|
|
124
|
+
];
|
|
125
|
+
expect(Array.isArray(healthCheckFormat)).toBe(true);
|
|
126
|
+
expect(healthCheckFormat[0]).toHaveProperty('category');
|
|
127
|
+
expect(healthCheckFormat[0]).toHaveProperty('status');
|
|
128
|
+
expect(healthCheckFormat[0]).toHaveProperty('message');
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
//# sourceMappingURL=mcp-server.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server.test.js","sourceRoot":"","sources":["../../src/__tests__/mcp-server.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-tools.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/schema-tools.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { jest, describe, it, expect, beforeEach, beforeAll } from '@jest/globals';
|
|
2
|
+
// Use jest.unstable_mockModule for ESM
|
|
3
|
+
const mockQuery = jest.fn();
|
|
4
|
+
const mockIsConnected = jest.fn();
|
|
5
|
+
jest.unstable_mockModule('../db-manager.js', () => ({
|
|
6
|
+
getDbManager: jest.fn(() => ({
|
|
7
|
+
query: mockQuery,
|
|
8
|
+
isConnected: mockIsConnected.mockReturnValue(true),
|
|
9
|
+
})),
|
|
10
|
+
resetDbManager: jest.fn(),
|
|
11
|
+
}));
|
|
12
|
+
// Dynamic import after mock
|
|
13
|
+
let listSchemas;
|
|
14
|
+
let listObjects;
|
|
15
|
+
let getObjectDetails;
|
|
16
|
+
beforeAll(async () => {
|
|
17
|
+
const module = await import('../tools/schema-tools.js');
|
|
18
|
+
listSchemas = module.listSchemas;
|
|
19
|
+
listObjects = module.listObjects;
|
|
20
|
+
getObjectDetails = module.getObjectDetails;
|
|
21
|
+
});
|
|
22
|
+
describe('Schema Tools', () => {
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
jest.clearAllMocks();
|
|
25
|
+
mockIsConnected.mockReturnValue(true);
|
|
26
|
+
});
|
|
27
|
+
describe('listSchemas', () => {
|
|
28
|
+
it('should list schemas without system schemas by default', async () => {
|
|
29
|
+
mockQuery.mockResolvedValue({
|
|
30
|
+
rows: [
|
|
31
|
+
{ schema_name: 'public', owner: 'postgres' },
|
|
32
|
+
{ schema_name: 'app', owner: 'app_user' }
|
|
33
|
+
]
|
|
34
|
+
});
|
|
35
|
+
const result = await listSchemas({});
|
|
36
|
+
expect(result).toHaveLength(2);
|
|
37
|
+
expect(result[0].schema_name).toBe('public');
|
|
38
|
+
// Verify the query excludes system schemas
|
|
39
|
+
const queryCall = mockQuery.mock.calls[0][0];
|
|
40
|
+
expect(queryCall).toContain('NOT IN');
|
|
41
|
+
expect(queryCall).toContain('pg_catalog');
|
|
42
|
+
});
|
|
43
|
+
it('should include system schemas when requested', async () => {
|
|
44
|
+
mockQuery.mockResolvedValue({
|
|
45
|
+
rows: [
|
|
46
|
+
{ schema_name: 'public', owner: 'postgres' },
|
|
47
|
+
{ schema_name: 'pg_catalog', owner: 'postgres' },
|
|
48
|
+
{ schema_name: 'information_schema', owner: 'postgres' }
|
|
49
|
+
]
|
|
50
|
+
});
|
|
51
|
+
const result = await listSchemas({ includeSystemSchemas: true });
|
|
52
|
+
expect(result).toHaveLength(3);
|
|
53
|
+
// Verify the query doesn't have the exclusion
|
|
54
|
+
const queryCall = mockQuery.mock.calls[0][0];
|
|
55
|
+
expect(queryCall).not.toContain('NOT IN');
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
describe('listObjects', () => {
|
|
59
|
+
it('should require schema parameter', async () => {
|
|
60
|
+
await expect(listObjects({ schema: '' }))
|
|
61
|
+
.rejects.toThrow('schema parameter is required');
|
|
62
|
+
await expect(listObjects({ schema: undefined }))
|
|
63
|
+
.rejects.toThrow('schema parameter is required');
|
|
64
|
+
});
|
|
65
|
+
it('should validate schema name', async () => {
|
|
66
|
+
await expect(listObjects({ schema: 'public; DROP TABLE users;--' }))
|
|
67
|
+
.rejects.toThrow('invalid characters');
|
|
68
|
+
await expect(listObjects({ schema: "schema'" }))
|
|
69
|
+
.rejects.toThrow('invalid characters');
|
|
70
|
+
});
|
|
71
|
+
it('should list all object types by default', async () => {
|
|
72
|
+
mockQuery
|
|
73
|
+
.mockResolvedValueOnce({ rows: [{ name: 'users', type: 'table', owner: 'app', schema: 'public' }] })
|
|
74
|
+
.mockResolvedValueOnce({ rows: [{ name: 'active_users', type: 'view', owner: '', schema: 'public' }] })
|
|
75
|
+
.mockResolvedValueOnce({ rows: [{ name: 'users_id_seq', type: 'sequence', owner: '', schema: 'public' }] })
|
|
76
|
+
.mockResolvedValueOnce({ rows: [] });
|
|
77
|
+
const result = await listObjects({ schema: 'public' });
|
|
78
|
+
expect(result).toHaveLength(3);
|
|
79
|
+
expect(mockQuery).toHaveBeenCalledTimes(4); // tables, views, sequences, extensions
|
|
80
|
+
});
|
|
81
|
+
it('should filter by object type', async () => {
|
|
82
|
+
mockQuery.mockResolvedValue({
|
|
83
|
+
rows: [{ name: 'users', type: 'table', owner: 'app', schema: 'public' }]
|
|
84
|
+
});
|
|
85
|
+
const result = await listObjects({ schema: 'public', objectType: 'table' });
|
|
86
|
+
expect(result).toHaveLength(1);
|
|
87
|
+
expect(mockQuery).toHaveBeenCalledTimes(1);
|
|
88
|
+
});
|
|
89
|
+
it('should validate filter parameter', async () => {
|
|
90
|
+
await expect(listObjects({ schema: 'public', filter: 'test; DROP TABLE' }))
|
|
91
|
+
.rejects.toThrow('filter contains invalid characters');
|
|
92
|
+
});
|
|
93
|
+
it('should reject filter that is too long', async () => {
|
|
94
|
+
const longFilter = 'a'.repeat(129);
|
|
95
|
+
await expect(listObjects({ schema: 'public', filter: longFilter }))
|
|
96
|
+
.rejects.toThrow('filter must be 128 characters or less');
|
|
97
|
+
});
|
|
98
|
+
it('should use parameterized queries for filter', async () => {
|
|
99
|
+
mockQuery.mockResolvedValue({ rows: [] });
|
|
100
|
+
await listObjects({ schema: 'public', objectType: 'table', filter: 'user' });
|
|
101
|
+
expect(mockQuery).toHaveBeenCalledWith(expect.stringContaining('ILIKE'), ['public', 'user']);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
describe('getObjectDetails', () => {
|
|
105
|
+
it('should require schema parameter', async () => {
|
|
106
|
+
await expect(getObjectDetails({ schema: '', objectName: 'users' }))
|
|
107
|
+
.rejects.toThrow('schema parameter is required');
|
|
108
|
+
});
|
|
109
|
+
it('should require objectName parameter', async () => {
|
|
110
|
+
await expect(getObjectDetails({ schema: 'public', objectName: '' }))
|
|
111
|
+
.rejects.toThrow('objectName parameter is required');
|
|
112
|
+
});
|
|
113
|
+
it('should validate schema name', async () => {
|
|
114
|
+
await expect(getObjectDetails({ schema: 'public; DROP', objectName: 'users' }))
|
|
115
|
+
.rejects.toThrow('invalid characters');
|
|
116
|
+
});
|
|
117
|
+
it('should validate object name', async () => {
|
|
118
|
+
await expect(getObjectDetails({ schema: 'public', objectName: 'users; DROP' }))
|
|
119
|
+
.rejects.toThrow('invalid characters');
|
|
120
|
+
});
|
|
121
|
+
it('should return columns, constraints, and indexes', async () => {
|
|
122
|
+
mockQuery
|
|
123
|
+
.mockResolvedValueOnce({
|
|
124
|
+
rows: [
|
|
125
|
+
{ column_name: 'id', data_type: 'integer', is_nullable: 'NO', column_default: null, character_maximum_length: null },
|
|
126
|
+
{ column_name: 'name', data_type: 'text', is_nullable: 'YES', column_default: null, character_maximum_length: null }
|
|
127
|
+
]
|
|
128
|
+
})
|
|
129
|
+
.mockResolvedValueOnce({
|
|
130
|
+
rows: [
|
|
131
|
+
{ constraint_name: 'users_pkey', constraint_type: 'PRIMARY KEY', table_name: 'users', column_name: 'id', foreign_table_name: null, foreign_column_name: null }
|
|
132
|
+
]
|
|
133
|
+
})
|
|
134
|
+
.mockResolvedValueOnce({
|
|
135
|
+
rows: [
|
|
136
|
+
{ index_name: 'users_pkey', index_definition: 'CREATE UNIQUE INDEX...', is_unique: true, is_primary: true }
|
|
137
|
+
]
|
|
138
|
+
})
|
|
139
|
+
.mockResolvedValueOnce({
|
|
140
|
+
rows: [{ size: '16 kB', row_count: 100 }]
|
|
141
|
+
});
|
|
142
|
+
const result = await getObjectDetails({ schema: 'public', objectName: 'users' });
|
|
143
|
+
expect(result.columns).toHaveLength(2);
|
|
144
|
+
expect(result.constraints).toHaveLength(1);
|
|
145
|
+
expect(result.indexes).toHaveLength(1);
|
|
146
|
+
expect(result.size).toBe('16 kB');
|
|
147
|
+
expect(result.rowCount).toBe(100);
|
|
148
|
+
});
|
|
149
|
+
it('should use parameterized queries', async () => {
|
|
150
|
+
mockQuery.mockResolvedValue({ rows: [] });
|
|
151
|
+
await getObjectDetails({ schema: 'public', objectName: 'users' });
|
|
152
|
+
// All queries should use parameters
|
|
153
|
+
mockQuery.mock.calls.forEach((call) => {
|
|
154
|
+
if (call[1]) {
|
|
155
|
+
expect(call[1]).toEqual(['public', 'users']);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
it('should get view definition when objectType is view', async () => {
|
|
160
|
+
mockQuery
|
|
161
|
+
.mockResolvedValueOnce({ rows: [] }) // columns
|
|
162
|
+
.mockResolvedValueOnce({ rows: [] }) // constraints
|
|
163
|
+
.mockResolvedValueOnce({ rows: [] }) // indexes
|
|
164
|
+
.mockResolvedValueOnce({ rows: [] }) // size
|
|
165
|
+
.mockResolvedValueOnce({ rows: [{ definition: 'SELECT * FROM users' }] }); // view def
|
|
166
|
+
const result = await getObjectDetails({ schema: 'public', objectName: 'active_users', objectType: 'view' });
|
|
167
|
+
expect(result.definition).toBe('SELECT * FROM users');
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
//# sourceMappingURL=schema-tools.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-tools.test.js","sourceRoot":"","sources":["../../src/__tests__/schema-tools.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-tools.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/server-tools.test.ts"],"names":[],"mappings":""}
|