@calebmabry/postgres-mcp-server 2.0.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/LICENSE +15 -0
- package/README.md +203 -0
- package/dist/config.d.ts +47 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +51 -0
- package/dist/config.js.map +1 -0
- package/dist/db.d.ts +46 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +142 -0
- package/dist/db.js.map +1 -0
- package/dist/http-server.d.ts +3 -0
- package/dist/http-server.d.ts.map +1 -0
- package/dist/http-server.js +184 -0
- package/dist/http-server.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +8 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +85 -0
- package/dist/logger.js.map +1 -0
- package/dist/register-tools.d.ts +6 -0
- package/dist/register-tools.d.ts.map +1 -0
- package/dist/register-tools.js +83 -0
- package/dist/register-tools.js.map +1 -0
- package/dist/tools/describe.d.ts +31 -0
- package/dist/tools/describe.d.ts.map +1 -0
- package/dist/tools/describe.js +61 -0
- package/dist/tools/describe.js.map +1 -0
- package/dist/tools/functions.d.ts +20 -0
- package/dist/tools/functions.d.ts.map +1 -0
- package/dist/tools/functions.js +65 -0
- package/dist/tools/functions.js.map +1 -0
- package/dist/tools/indexes.d.ts +17 -0
- package/dist/tools/indexes.d.ts.map +1 -0
- package/dist/tools/indexes.js +82 -0
- package/dist/tools/indexes.js.map +1 -0
- package/dist/tools/list.d.ts +22 -0
- package/dist/tools/list.d.ts.map +1 -0
- package/dist/tools/list.js +64 -0
- package/dist/tools/list.js.map +1 -0
- package/dist/tools/performance.d.ts +26 -0
- package/dist/tools/performance.d.ts.map +1 -0
- package/dist/tools/performance.js +125 -0
- package/dist/tools/performance.js.map +1 -0
- package/dist/tools/query.d.ts +6 -0
- package/dist/tools/query.d.ts.map +1 -0
- package/dist/tools/query.js +318 -0
- package/dist/tools/query.js.map +1 -0
- package/dist/tools/schemas.d.ts +10 -0
- package/dist/tools/schemas.d.ts.map +1 -0
- package/dist/tools/schemas.js +51 -0
- package/dist/tools/schemas.js.map +1 -0
- package/dist/validation.d.ts +159 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +90 -0
- package/dist/validation.js.map +1 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +11 -0
- package/dist/version.js.map +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
4
|
+
import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
|
|
5
|
+
import { randomUUID } from "crypto";
|
|
6
|
+
import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
|
|
7
|
+
import { config } from "./config.js";
|
|
8
|
+
import { registerTools } from "./register-tools.js";
|
|
9
|
+
import { closeDb } from "./db.js";
|
|
10
|
+
import { log } from "./logger.js";
|
|
11
|
+
import { VERSION, PACKAGE_NAME } from "./version.js";
|
|
12
|
+
// Store active transports by session ID
|
|
13
|
+
const transports = {};
|
|
14
|
+
function createServer() {
|
|
15
|
+
const server = new McpServer({
|
|
16
|
+
name: PACKAGE_NAME,
|
|
17
|
+
version: VERSION,
|
|
18
|
+
}, {
|
|
19
|
+
capabilities: {
|
|
20
|
+
tools: {},
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
registerTools(server);
|
|
24
|
+
return server;
|
|
25
|
+
}
|
|
26
|
+
const PORT = config.server.port;
|
|
27
|
+
// Get allowed hosts from environment variable or use defaults
|
|
28
|
+
const allowedHostsEnv = config.server.allowedHosts;
|
|
29
|
+
const allowedHosts = allowedHostsEnv
|
|
30
|
+
? allowedHostsEnv.split(',').map(h => h.trim())
|
|
31
|
+
: undefined;
|
|
32
|
+
const app = createMcpExpressApp({
|
|
33
|
+
host: '0.0.0.0',
|
|
34
|
+
allowedHosts
|
|
35
|
+
});
|
|
36
|
+
app.get("/health", (req, res) => {
|
|
37
|
+
res.json({ status: "ok", timestamp: new Date().toISOString() });
|
|
38
|
+
});
|
|
39
|
+
const mcpPostHandler = async (req, res) => {
|
|
40
|
+
try {
|
|
41
|
+
let sessionId = req.headers["mcp-session-id"];
|
|
42
|
+
// Check if this is an initialization request
|
|
43
|
+
const isInit = isInitializeRequest(req.body);
|
|
44
|
+
if (isInit) {
|
|
45
|
+
// Create new session for initialization
|
|
46
|
+
sessionId = randomUUID();
|
|
47
|
+
log.info(`New session created: ${sessionId}`, "http");
|
|
48
|
+
const transport = new StreamableHTTPServerTransport({
|
|
49
|
+
sessionIdGenerator: () => sessionId,
|
|
50
|
+
});
|
|
51
|
+
const server = createServer();
|
|
52
|
+
await server.connect(transport);
|
|
53
|
+
transports[sessionId] = transport;
|
|
54
|
+
// Clean up on transport close
|
|
55
|
+
const capturedSessionId = sessionId;
|
|
56
|
+
transport.onclose = () => {
|
|
57
|
+
log.info(`Session ${capturedSessionId} closed`, "http");
|
|
58
|
+
delete transports[capturedSessionId];
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
else if (!sessionId || !transports[sessionId]) {
|
|
62
|
+
res.status(400).json({
|
|
63
|
+
jsonrpc: "2.0",
|
|
64
|
+
error: {
|
|
65
|
+
code: -32600,
|
|
66
|
+
message: "Invalid or missing session ID",
|
|
67
|
+
},
|
|
68
|
+
id: null,
|
|
69
|
+
});
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const transport = transports[sessionId];
|
|
73
|
+
await transport.handleRequest(req, res, req.body);
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
log.error("Error handling MCP request", "http", error);
|
|
77
|
+
if (!res.headersSent) {
|
|
78
|
+
res.status(500).json({
|
|
79
|
+
jsonrpc: "2.0",
|
|
80
|
+
error: {
|
|
81
|
+
code: -32603,
|
|
82
|
+
message: "Internal server error",
|
|
83
|
+
},
|
|
84
|
+
id: null,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
app.post("/mcp", mcpPostHandler);
|
|
90
|
+
// MCP GET handler for SSE streaming
|
|
91
|
+
const mcpGetHandler = async (req, res) => {
|
|
92
|
+
const sessionId = req.headers["mcp-session-id"];
|
|
93
|
+
if (!sessionId || !transports[sessionId]) {
|
|
94
|
+
res.status(400).send("Invalid or missing session ID");
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const lastEventId = req.headers["last-event-id"];
|
|
98
|
+
if (lastEventId) {
|
|
99
|
+
log.debug(`Client reconnecting with Last-Event-ID: ${lastEventId}`, "http");
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
log.info(`Establishing SSE stream for session ${sessionId}`, "http");
|
|
103
|
+
}
|
|
104
|
+
// Set headers for SSE
|
|
105
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
106
|
+
res.setHeader('Connection', 'keep-alive');
|
|
107
|
+
// Handle client disconnect
|
|
108
|
+
req.on('close', () => {
|
|
109
|
+
log.info(`Client disconnected SSE stream for session ${sessionId}`, "http");
|
|
110
|
+
});
|
|
111
|
+
const transport = transports[sessionId];
|
|
112
|
+
await transport.handleRequest(req, res);
|
|
113
|
+
};
|
|
114
|
+
app.get("/mcp", mcpGetHandler);
|
|
115
|
+
// MCP DELETE handler for session termination
|
|
116
|
+
const mcpDeleteHandler = async (req, res) => {
|
|
117
|
+
const sessionId = req.headers["mcp-session-id"];
|
|
118
|
+
if (!sessionId || !transports[sessionId]) {
|
|
119
|
+
res.status(400).send("Invalid or missing session ID");
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
log.info(`Session termination requested: ${sessionId}`, "http");
|
|
123
|
+
try {
|
|
124
|
+
const transport = transports[sessionId];
|
|
125
|
+
await transport.handleRequest(req, res);
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
log.error(`Error handling session termination for ${sessionId}`, "http", error);
|
|
129
|
+
if (!res.headersSent) {
|
|
130
|
+
res.status(500).send("Error processing session termination");
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
app.delete("/mcp", mcpDeleteHandler);
|
|
135
|
+
log.banner("http", VERSION);
|
|
136
|
+
const server = app.listen(PORT, () => {
|
|
137
|
+
log.info(`Listening on http://localhost:${PORT}`, "http");
|
|
138
|
+
log.info(`MCP endpoint: http://localhost:${PORT}/mcp`, "http");
|
|
139
|
+
log.info(`Health check: http://localhost:${PORT}/health`, "http");
|
|
140
|
+
});
|
|
141
|
+
// Configure keepalive timeout for long-running SSE connections
|
|
142
|
+
server.keepAliveTimeout = 65000; // 65 seconds
|
|
143
|
+
server.headersTimeout = 66000; // Slightly longer than keepAlive
|
|
144
|
+
server.on("error", (error) => {
|
|
145
|
+
if (error.code === "EADDRINUSE") {
|
|
146
|
+
log.error(`Port ${PORT} is already in use. Set a different PORT env var.`, "http");
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
log.error("Server error", "http", error);
|
|
150
|
+
}
|
|
151
|
+
process.exit(1);
|
|
152
|
+
});
|
|
153
|
+
process.on("uncaughtException", (error) => {
|
|
154
|
+
log.error("Uncaught exception", "http", error);
|
|
155
|
+
process.exit(1);
|
|
156
|
+
});
|
|
157
|
+
process.on("unhandledRejection", (reason, promise) => {
|
|
158
|
+
log.error("Unhandled rejection", "http", { reason, promise });
|
|
159
|
+
process.exit(1);
|
|
160
|
+
});
|
|
161
|
+
process.on("SIGINT", async () => {
|
|
162
|
+
log.warn("Shutting down server...", "http");
|
|
163
|
+
server.close(() => {
|
|
164
|
+
log.info("HTTP server closed", "http");
|
|
165
|
+
});
|
|
166
|
+
for (const sessionId in transports) {
|
|
167
|
+
try {
|
|
168
|
+
log.debug(`Closing transport for session ${sessionId}`, "http");
|
|
169
|
+
await transports[sessionId].close();
|
|
170
|
+
delete transports[sessionId];
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
log.error(`Error closing transport for session ${sessionId}`, "http", error);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
await closeDb();
|
|
177
|
+
log.info("Server shutdown complete", "http");
|
|
178
|
+
process.exit(0);
|
|
179
|
+
});
|
|
180
|
+
process.on("SIGTERM", async () => {
|
|
181
|
+
log.warn("Received SIGTERM signal...", "http");
|
|
182
|
+
process.emit("SIGINT");
|
|
183
|
+
});
|
|
184
|
+
//# sourceMappingURL=http-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-server.js","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { registerTools } from "./register-tools.js";
|
|
5
|
+
import { closeDb } from "./db.js";
|
|
6
|
+
import { log } from "./logger.js";
|
|
7
|
+
import { VERSION, PACKAGE_NAME } from "./version.js";
|
|
8
|
+
async function shutdown() {
|
|
9
|
+
await closeDb();
|
|
10
|
+
process.exit(0);
|
|
11
|
+
}
|
|
12
|
+
process.on("SIGINT", shutdown);
|
|
13
|
+
process.on("SIGTERM", shutdown);
|
|
14
|
+
async function main() {
|
|
15
|
+
log.banner("stdio", VERSION);
|
|
16
|
+
const server = new McpServer({
|
|
17
|
+
name: PACKAGE_NAME,
|
|
18
|
+
version: VERSION,
|
|
19
|
+
}, {
|
|
20
|
+
capabilities: {
|
|
21
|
+
tools: {},
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
registerTools(server);
|
|
25
|
+
const transport = new StdioServerTransport();
|
|
26
|
+
await server.connect(transport);
|
|
27
|
+
log.info("Server connected via stdio transport", "mcp");
|
|
28
|
+
}
|
|
29
|
+
main().catch((error) => {
|
|
30
|
+
log.error("Server error", "mcp", error);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
});
|
|
33
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAErD,KAAK,UAAU,QAAQ;IACrB,MAAM,OAAO,EAAE,CAAC;IAChB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAEhC,KAAK,UAAU,IAAI;IACjB,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAE7B,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B;QACE,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,OAAO;KACjB,EACD;QACE,YAAY,EAAE;YACZ,KAAK,EAAE,EAAE;SACV;KACF,CACF,CAAC;IACF,aAAa,CAAC,MAAM,CAAC,CAAC;IAEtB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,GAAG,CAAC,IAAI,CAAC,sCAAsC,EAAE,KAAK,CAAC,CAAC;AAC1D,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,GAAG,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IACxC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const log: {
|
|
2
|
+
debug: (msg: string, ctx?: string, extra?: unknown) => void;
|
|
3
|
+
info: (msg: string, ctx?: string, extra?: unknown) => void;
|
|
4
|
+
warn: (msg: string, ctx?: string, extra?: unknown) => void;
|
|
5
|
+
error: (msg: string, ctx?: string, extra?: unknown) => void;
|
|
6
|
+
banner(mode: "stdio" | "http", version: string): void;
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AA0EA,eAAO,MAAM,GAAG;iBACD,MAAM,QAAQ,MAAM,UAAU,OAAO;gBACrC,MAAM,QAAQ,MAAM,UAAU,OAAO;gBACrC,MAAM,QAAQ,MAAM,UAAU,OAAO;iBACrC,MAAM,QAAQ,MAAM,UAAU,OAAO;iBAErC,OAAO,GAAG,MAAM,WAAW,MAAM;CAiB/C,CAAC"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { config } from "./config.js";
|
|
2
|
+
const LOG_LEVELS = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
3
|
+
const currentLevel = config.app.logLevel;
|
|
4
|
+
// ANSI escape helpers
|
|
5
|
+
const esc = (code) => `\x1b[${code}m`;
|
|
6
|
+
const reset = esc("0");
|
|
7
|
+
const dim = esc("2");
|
|
8
|
+
const bold = esc("1");
|
|
9
|
+
const colors = {
|
|
10
|
+
cyan: esc("36"),
|
|
11
|
+
green: esc("32"),
|
|
12
|
+
yellow: esc("33"),
|
|
13
|
+
red: esc("31"),
|
|
14
|
+
magenta: esc("35"),
|
|
15
|
+
blue: esc("34"),
|
|
16
|
+
white: esc("37"),
|
|
17
|
+
gray: esc("90"),
|
|
18
|
+
};
|
|
19
|
+
const levelStyles = {
|
|
20
|
+
debug: { symbol: "◆", color: colors.magenta, label: "DEBUG" },
|
|
21
|
+
info: { symbol: "●", color: colors.cyan, label: "INFO " },
|
|
22
|
+
warn: { symbol: "▲", color: colors.yellow, label: "WARN " },
|
|
23
|
+
error: { symbol: "✖", color: colors.red, label: "ERROR" },
|
|
24
|
+
};
|
|
25
|
+
const contextColors = {
|
|
26
|
+
db: colors.green,
|
|
27
|
+
mcp: colors.blue,
|
|
28
|
+
http: colors.cyan,
|
|
29
|
+
query: colors.magenta,
|
|
30
|
+
tool: colors.yellow,
|
|
31
|
+
};
|
|
32
|
+
function timestamp() {
|
|
33
|
+
const now = new Date();
|
|
34
|
+
const h = String(now.getHours()).padStart(2, "0");
|
|
35
|
+
const m = String(now.getMinutes()).padStart(2, "0");
|
|
36
|
+
const s = String(now.getSeconds()).padStart(2, "0");
|
|
37
|
+
const ms = String(now.getMilliseconds()).padStart(3, "0");
|
|
38
|
+
return `${h}:${m}:${s}.${ms}`;
|
|
39
|
+
}
|
|
40
|
+
function formatContext(ctx) {
|
|
41
|
+
if (!ctx)
|
|
42
|
+
return "";
|
|
43
|
+
const c = contextColors[ctx] || colors.white;
|
|
44
|
+
return ` ${c}[${ctx}]${reset}`;
|
|
45
|
+
}
|
|
46
|
+
function write(level, msg, ctx, extra) {
|
|
47
|
+
if (LOG_LEVELS[level] < LOG_LEVELS[currentLevel])
|
|
48
|
+
return;
|
|
49
|
+
const style = levelStyles[level];
|
|
50
|
+
const ts = `${dim}${timestamp()}${reset}`;
|
|
51
|
+
const badge = `${style.color}${bold}${style.symbol} ${style.label}${reset}`;
|
|
52
|
+
const context = formatContext(ctx);
|
|
53
|
+
let line = `${ts} ${badge}${context} ${msg}`;
|
|
54
|
+
if (extra !== undefined) {
|
|
55
|
+
if (extra instanceof Error) {
|
|
56
|
+
line += `\n${dim} ${extra.stack || extra.message}${reset}`;
|
|
57
|
+
}
|
|
58
|
+
else if (typeof extra === "object") {
|
|
59
|
+
line += `\n${dim} ${JSON.stringify(extra, null, 2).split("\n").join(`\n `)}${reset}`;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
process.stderr.write(line + "\n");
|
|
63
|
+
}
|
|
64
|
+
export const log = {
|
|
65
|
+
debug: (msg, ctx, extra) => write("debug", msg, ctx, extra),
|
|
66
|
+
info: (msg, ctx, extra) => write("info", msg, ctx, extra),
|
|
67
|
+
warn: (msg, ctx, extra) => write("warn", msg, ctx, extra),
|
|
68
|
+
error: (msg, ctx, extra) => write("error", msg, ctx, extra),
|
|
69
|
+
banner(mode, version) {
|
|
70
|
+
const readOnly = config.app.readOnly ? "read-only" : "read-write";
|
|
71
|
+
const logLevel = currentLevel;
|
|
72
|
+
const lines = [
|
|
73
|
+
`${bold}${colors.cyan}┌─────────────────────────────────────────┐${reset}`,
|
|
74
|
+
`${bold}${colors.cyan}│${reset} ${bold}${colors.white}⚡ postgres-mcp-server${reset}${" ".repeat(19)}${bold}${colors.cyan}│${reset}`,
|
|
75
|
+
`${bold}${colors.cyan}├─────────────────────────────────────────┤${reset}`,
|
|
76
|
+
`${bold}${colors.cyan}│${reset} ${dim}version${reset} ${colors.green}${version.padEnd(28)}${reset}${bold}${colors.cyan}│${reset}`,
|
|
77
|
+
`${bold}${colors.cyan}│${reset} ${dim}transport${reset} ${colors.green}${mode.padEnd(28)}${reset}${bold}${colors.cyan}│${reset}`,
|
|
78
|
+
`${bold}${colors.cyan}│${reset} ${dim}mode${reset} ${colors.green}${readOnly.padEnd(28)}${reset}${bold}${colors.cyan}│${reset}`,
|
|
79
|
+
`${bold}${colors.cyan}│${reset} ${dim}log level${reset} ${colors.green}${logLevel.padEnd(28)}${reset}${bold}${colors.cyan}│${reset}`,
|
|
80
|
+
`${bold}${colors.cyan}└─────────────────────────────────────────┘${reset}`,
|
|
81
|
+
];
|
|
82
|
+
process.stderr.write("\n" + lines.join("\n") + "\n\n");
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-tools.d.ts","sourceRoot":"","sources":["../src/register-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA6CzE;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,QA2D9C"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { config } from "./config.js";
|
|
2
|
+
import { QueryInputSchema, DescribeTableInputSchema, ListTablesInputSchema, ListSchemasInputSchema, ListIndexesInputSchema, ExplainQueryInputSchema, GetTableStatsInputSchema, ListViewsInputSchema, ListFunctionsInputSchema, } from "./validation.js";
|
|
3
|
+
import { queryTool, MAX_PAGE_SIZE, DEFAULT_PAGE_SIZE, MAX_PAYLOAD_SIZE } from "./tools/query.js";
|
|
4
|
+
import { describeTableTool, getConstraintsTool } from "./tools/describe.js";
|
|
5
|
+
import { listTablesTool, listViewsTool } from "./tools/list.js";
|
|
6
|
+
import { listSchemasTool } from "./tools/schemas.js";
|
|
7
|
+
import { listIndexesTool } from "./tools/indexes.js";
|
|
8
|
+
import { explainQueryTool, getTableStatsTool } from "./tools/performance.js";
|
|
9
|
+
import { listFunctionsTool } from "./tools/functions.js";
|
|
10
|
+
import { log } from "./logger.js";
|
|
11
|
+
function wrapTool(name, fn) {
|
|
12
|
+
return async (args) => {
|
|
13
|
+
log.info(`${name}`, "tool");
|
|
14
|
+
log.debug(`${name} args`, "tool", args);
|
|
15
|
+
const start = performance.now();
|
|
16
|
+
const result = await fn(args);
|
|
17
|
+
const ms = (performance.now() - start).toFixed(1);
|
|
18
|
+
if (result.error) {
|
|
19
|
+
log.warn(`${name} failed (${ms}ms): ${result.error}`, "tool");
|
|
20
|
+
return {
|
|
21
|
+
content: [{ type: "text", text: `Error: ${result.error}` }],
|
|
22
|
+
isError: true,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
log.info(`${name} completed (${ms}ms)`, "tool");
|
|
26
|
+
return {
|
|
27
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Register all PostgreSQL tools on an MCP server instance
|
|
33
|
+
*/
|
|
34
|
+
export function registerTools(server) {
|
|
35
|
+
const maxPayloadMB = (MAX_PAYLOAD_SIZE / (1024 * 1024)).toFixed(1);
|
|
36
|
+
const readOnlyMode = config.app.readOnly;
|
|
37
|
+
const queryDescription = `Execute SQL queries with pagination support and parameterized queries for security. ` +
|
|
38
|
+
`Configuration: max ${MAX_PAGE_SIZE} rows/page (default ${DEFAULT_PAGE_SIZE}), max ${maxPayloadMB}MB payload size. ` +
|
|
39
|
+
`${readOnlyMode ? "READ-ONLY mode: only SELECT, WITH, and EXPLAIN queries allowed. " : ""}` +
|
|
40
|
+
`Pagination automatically applied to SELECT queries without LIMIT/OFFSET.`;
|
|
41
|
+
server.registerTool("query", {
|
|
42
|
+
description: queryDescription,
|
|
43
|
+
inputSchema: QueryInputSchema,
|
|
44
|
+
}, wrapTool("query", queryTool));
|
|
45
|
+
server.registerTool("describe_table", {
|
|
46
|
+
description: "Get the structure of a database table",
|
|
47
|
+
inputSchema: DescribeTableInputSchema,
|
|
48
|
+
}, wrapTool("describe_table", describeTableTool));
|
|
49
|
+
server.registerTool("list_tables", {
|
|
50
|
+
description: "List all tables in a schema",
|
|
51
|
+
inputSchema: ListTablesInputSchema,
|
|
52
|
+
}, wrapTool("list_tables", listTablesTool));
|
|
53
|
+
server.registerTool("get_constraints", {
|
|
54
|
+
description: "Get constraints for a table",
|
|
55
|
+
inputSchema: DescribeTableInputSchema,
|
|
56
|
+
}, wrapTool("get_constraints", getConstraintsTool));
|
|
57
|
+
server.registerTool("list_schemas", {
|
|
58
|
+
description: "List all schemas in the database",
|
|
59
|
+
inputSchema: ListSchemasInputSchema,
|
|
60
|
+
}, wrapTool("list_schemas", listSchemasTool));
|
|
61
|
+
server.registerTool("list_indexes", {
|
|
62
|
+
description: "List indexes for a table or schema",
|
|
63
|
+
inputSchema: ListIndexesInputSchema,
|
|
64
|
+
}, wrapTool("list_indexes", listIndexesTool));
|
|
65
|
+
server.registerTool("explain_query", {
|
|
66
|
+
description: "Get query execution plan (EXPLAIN)",
|
|
67
|
+
inputSchema: ExplainQueryInputSchema,
|
|
68
|
+
}, wrapTool("explain_query", explainQueryTool));
|
|
69
|
+
server.registerTool("get_table_stats", {
|
|
70
|
+
description: "Get table statistics and size information",
|
|
71
|
+
inputSchema: GetTableStatsInputSchema,
|
|
72
|
+
}, wrapTool("get_table_stats", getTableStatsTool));
|
|
73
|
+
server.registerTool("list_views", {
|
|
74
|
+
description: "List views in a schema",
|
|
75
|
+
inputSchema: ListViewsInputSchema,
|
|
76
|
+
}, wrapTool("list_views", listViewsTool));
|
|
77
|
+
server.registerTool("list_functions", {
|
|
78
|
+
description: "List functions and procedures in a schema",
|
|
79
|
+
inputSchema: ListFunctionsInputSchema,
|
|
80
|
+
}, wrapTool("list_functions", listFunctionsTool));
|
|
81
|
+
log.info(`Registered 10 tools`, "mcp");
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=register-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-tools.js","sourceRoot":"","sources":["../src/register-tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface DescribeTableInput {
|
|
2
|
+
schema: string;
|
|
3
|
+
table: string;
|
|
4
|
+
}
|
|
5
|
+
export interface ColumnInfo {
|
|
6
|
+
column_name: string;
|
|
7
|
+
data_type: string;
|
|
8
|
+
character_maximum_length: number | null;
|
|
9
|
+
is_nullable: string;
|
|
10
|
+
column_default: string | null;
|
|
11
|
+
}
|
|
12
|
+
export interface DescribeTableOutput {
|
|
13
|
+
columns?: ColumnInfo[];
|
|
14
|
+
error?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function describeTableTool(input: DescribeTableInput): Promise<DescribeTableOutput>;
|
|
17
|
+
export interface GetConstraintsInput {
|
|
18
|
+
schema: string;
|
|
19
|
+
table: string;
|
|
20
|
+
}
|
|
21
|
+
export interface ConstraintInfo {
|
|
22
|
+
constraint_name: string;
|
|
23
|
+
constraint_type: string;
|
|
24
|
+
constraint_definition: string;
|
|
25
|
+
}
|
|
26
|
+
export interface GetConstraintsOutput {
|
|
27
|
+
constraints?: ConstraintInfo[];
|
|
28
|
+
error?: string;
|
|
29
|
+
}
|
|
30
|
+
export declare function getConstraintsTool(input: GetConstraintsInput): Promise<GetConstraintsOutput>;
|
|
31
|
+
//# sourceMappingURL=describe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"describe.d.ts","sourceRoot":"","sources":["../../src/tools/describe.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,wBAAwB,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA2B/F;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,qBAAqB,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,oBAAoB;IACnC,WAAW,CAAC,EAAE,cAAc,EAAE,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAiClG"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { getDb } from '../db.js';
|
|
2
|
+
import { sql } from 'kysely';
|
|
3
|
+
export async function describeTableTool(input) {
|
|
4
|
+
try {
|
|
5
|
+
const db = getDb();
|
|
6
|
+
const query = sql `
|
|
7
|
+
SELECT
|
|
8
|
+
column_name,
|
|
9
|
+
data_type,
|
|
10
|
+
character_maximum_length,
|
|
11
|
+
is_nullable,
|
|
12
|
+
column_default
|
|
13
|
+
FROM information_schema.columns
|
|
14
|
+
WHERE table_schema = ${input.schema}
|
|
15
|
+
AND table_name = ${input.table}
|
|
16
|
+
ORDER BY ordinal_position
|
|
17
|
+
`;
|
|
18
|
+
const result = await query.execute(db);
|
|
19
|
+
return {
|
|
20
|
+
columns: result.rows,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
return {
|
|
25
|
+
error: error instanceof Error ? error.message : 'Unknown error occurred',
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export async function getConstraintsTool(input) {
|
|
30
|
+
try {
|
|
31
|
+
const db = getDb();
|
|
32
|
+
const query = sql `
|
|
33
|
+
SELECT
|
|
34
|
+
c.conname as constraint_name,
|
|
35
|
+
CASE c.contype
|
|
36
|
+
WHEN 'p' THEN 'PRIMARY KEY'
|
|
37
|
+
WHEN 'f' THEN 'FOREIGN KEY'
|
|
38
|
+
WHEN 'u' THEN 'UNIQUE'
|
|
39
|
+
WHEN 'c' THEN 'CHECK'
|
|
40
|
+
ELSE c.contype
|
|
41
|
+
END as constraint_type,
|
|
42
|
+
pg_get_constraintdef(c.oid) as constraint_definition
|
|
43
|
+
FROM pg_constraint c
|
|
44
|
+
JOIN pg_namespace n ON n.oid = c.connamespace
|
|
45
|
+
JOIN pg_class cl ON cl.oid = c.conrelid
|
|
46
|
+
WHERE n.nspname = ${input.schema}
|
|
47
|
+
AND cl.relname = ${input.table}
|
|
48
|
+
ORDER BY c.conname
|
|
49
|
+
`;
|
|
50
|
+
const result = await query.execute(db);
|
|
51
|
+
return {
|
|
52
|
+
constraints: result.rows,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
return {
|
|
57
|
+
error: error instanceof Error ? error.message : 'Unknown error occurred',
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=describe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"describe.js","sourceRoot":"","sources":["../../src/tools/describe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACjC,OAAO,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAoB7B,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,KAAyB;IAC/D,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;QAEnB,MAAM,KAAK,GAAG,GAAG,CAAY;;;;;;;;6BAQJ,KAAK,CAAC,MAAM;2BACd,KAAK,CAAC,KAAK;;KAEjC,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAEvC,OAAO;YACL,OAAO,EAAE,MAAM,CAAC,IAAI;SACrB,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB;SACzE,CAAC;IACJ,CAAC;AACH,CAAC;AAkBD,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,KAA0B;IACjE,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;QAEnB,MAAM,KAAK,GAAG,GAAG,CAAgB;;;;;;;;;;;;;;0BAcX,KAAK,CAAC,MAAM;2BACX,KAAK,CAAC,KAAK;;KAEjC,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAEvC,OAAO;YACL,WAAW,EAAE,MAAM,CAAC,IAAI;SACzB,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB;SACzE,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface FunctionInfo {
|
|
2
|
+
schema_name: string;
|
|
3
|
+
function_name: string;
|
|
4
|
+
return_type: string;
|
|
5
|
+
argument_types: string;
|
|
6
|
+
function_type: string;
|
|
7
|
+
language: string;
|
|
8
|
+
is_aggregate: boolean;
|
|
9
|
+
is_window: boolean;
|
|
10
|
+
security_type: string;
|
|
11
|
+
volatility: string;
|
|
12
|
+
parallel_safety: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ListFunctionsOutput {
|
|
16
|
+
functions?: FunctionInfo[];
|
|
17
|
+
error?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function listFunctionsTool(input: unknown): Promise<ListFunctionsOutput>;
|
|
20
|
+
//# sourceMappingURL=functions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"functions.d.ts","sourceRoot":"","sources":["../../src/tools/functions.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,YAAY,EAAE,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA+DpF"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { getDb } from '../db.js';
|
|
2
|
+
import { sql } from 'kysely';
|
|
3
|
+
import { ListFunctionsInputSchema, validateInput } from '../validation.js';
|
|
4
|
+
export async function listFunctionsTool(input) {
|
|
5
|
+
try {
|
|
6
|
+
// Validate input
|
|
7
|
+
const validation = validateInput(ListFunctionsInputSchema, input);
|
|
8
|
+
if (!validation.success) {
|
|
9
|
+
return { error: `Input validation failed: ${validation.error}` };
|
|
10
|
+
}
|
|
11
|
+
const validatedInput = validation.data;
|
|
12
|
+
const db = getDb();
|
|
13
|
+
const schema = validatedInput.schema || 'public';
|
|
14
|
+
const query = sql `
|
|
15
|
+
SELECT
|
|
16
|
+
n.nspname as schema_name,
|
|
17
|
+
p.proname as function_name,
|
|
18
|
+
pg_get_function_result(p.oid) as return_type,
|
|
19
|
+
pg_get_function_arguments(p.oid) as argument_types,
|
|
20
|
+
CASE p.prokind
|
|
21
|
+
WHEN 'f' THEN 'function'
|
|
22
|
+
WHEN 'p' THEN 'procedure'
|
|
23
|
+
WHEN 'a' THEN 'aggregate'
|
|
24
|
+
WHEN 'w' THEN 'window'
|
|
25
|
+
ELSE 'unknown'
|
|
26
|
+
END as function_type,
|
|
27
|
+
l.lanname as language,
|
|
28
|
+
CASE WHEN p.prokind = 'a' THEN true ELSE false END as is_aggregate,
|
|
29
|
+
CASE WHEN p.prokind = 'w' THEN true ELSE false END as is_window,
|
|
30
|
+
CASE p.prosecdef
|
|
31
|
+
WHEN true THEN 'definer'
|
|
32
|
+
ELSE 'invoker'
|
|
33
|
+
END as security_type,
|
|
34
|
+
CASE p.provolatile
|
|
35
|
+
WHEN 'i' THEN 'immutable'
|
|
36
|
+
WHEN 's' THEN 'stable'
|
|
37
|
+
WHEN 'v' THEN 'volatile'
|
|
38
|
+
ELSE 'unknown'
|
|
39
|
+
END as volatility,
|
|
40
|
+
CASE p.proparallel
|
|
41
|
+
WHEN 's' THEN 'safe'
|
|
42
|
+
WHEN 'r' THEN 'restricted'
|
|
43
|
+
WHEN 'u' THEN 'unsafe'
|
|
44
|
+
ELSE 'unknown'
|
|
45
|
+
END as parallel_safety,
|
|
46
|
+
obj_description(p.oid) as description
|
|
47
|
+
FROM pg_proc p
|
|
48
|
+
JOIN pg_namespace n ON n.oid = p.pronamespace
|
|
49
|
+
JOIN pg_language l ON l.oid = p.prolang
|
|
50
|
+
WHERE n.nspname = ${schema}
|
|
51
|
+
AND p.prokind IN ('f', 'p', 'a', 'w')
|
|
52
|
+
ORDER BY function_type, function_name
|
|
53
|
+
`;
|
|
54
|
+
const result = await query.execute(db);
|
|
55
|
+
return {
|
|
56
|
+
functions: result.rows,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
return {
|
|
61
|
+
error: error instanceof Error ? error.message : 'Unknown error occurred',
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=functions.js.map
|