@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.
Files changed (63) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +203 -0
  3. package/dist/config.d.ts +47 -0
  4. package/dist/config.d.ts.map +1 -0
  5. package/dist/config.js +51 -0
  6. package/dist/config.js.map +1 -0
  7. package/dist/db.d.ts +46 -0
  8. package/dist/db.d.ts.map +1 -0
  9. package/dist/db.js +142 -0
  10. package/dist/db.js.map +1 -0
  11. package/dist/http-server.d.ts +3 -0
  12. package/dist/http-server.d.ts.map +1 -0
  13. package/dist/http-server.js +184 -0
  14. package/dist/http-server.js.map +1 -0
  15. package/dist/index.d.ts +3 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +33 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/logger.d.ts +8 -0
  20. package/dist/logger.d.ts.map +1 -0
  21. package/dist/logger.js +85 -0
  22. package/dist/logger.js.map +1 -0
  23. package/dist/register-tools.d.ts +6 -0
  24. package/dist/register-tools.d.ts.map +1 -0
  25. package/dist/register-tools.js +83 -0
  26. package/dist/register-tools.js.map +1 -0
  27. package/dist/tools/describe.d.ts +31 -0
  28. package/dist/tools/describe.d.ts.map +1 -0
  29. package/dist/tools/describe.js +61 -0
  30. package/dist/tools/describe.js.map +1 -0
  31. package/dist/tools/functions.d.ts +20 -0
  32. package/dist/tools/functions.d.ts.map +1 -0
  33. package/dist/tools/functions.js +65 -0
  34. package/dist/tools/functions.js.map +1 -0
  35. package/dist/tools/indexes.d.ts +17 -0
  36. package/dist/tools/indexes.d.ts.map +1 -0
  37. package/dist/tools/indexes.js +82 -0
  38. package/dist/tools/indexes.js.map +1 -0
  39. package/dist/tools/list.d.ts +22 -0
  40. package/dist/tools/list.d.ts.map +1 -0
  41. package/dist/tools/list.js +64 -0
  42. package/dist/tools/list.js.map +1 -0
  43. package/dist/tools/performance.d.ts +26 -0
  44. package/dist/tools/performance.d.ts.map +1 -0
  45. package/dist/tools/performance.js +125 -0
  46. package/dist/tools/performance.js.map +1 -0
  47. package/dist/tools/query.d.ts +6 -0
  48. package/dist/tools/query.d.ts.map +1 -0
  49. package/dist/tools/query.js +318 -0
  50. package/dist/tools/query.js.map +1 -0
  51. package/dist/tools/schemas.d.ts +10 -0
  52. package/dist/tools/schemas.d.ts.map +1 -0
  53. package/dist/tools/schemas.js +51 -0
  54. package/dist/tools/schemas.js.map +1 -0
  55. package/dist/validation.d.ts +159 -0
  56. package/dist/validation.d.ts.map +1 -0
  57. package/dist/validation.js +90 -0
  58. package/dist/validation.js.map +1 -0
  59. package/dist/version.d.ts +3 -0
  60. package/dist/version.d.ts.map +1 -0
  61. package/dist/version.js +11 -0
  62. package/dist/version.js.map +1 -0
  63. 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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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -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"}
@@ -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,6 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ /**
3
+ * Register all PostgreSQL tools on an MCP server instance
4
+ */
5
+ export declare function registerTools(server: McpServer): void;
6
+ //# sourceMappingURL=register-tools.d.ts.map
@@ -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