@marcelo-ochoa/server-postgres 0.6.2 → 0.6.3

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 CHANGED
@@ -21,7 +21,10 @@ A Model Context Protocol server that provides read-only access to PostgreSQL dat
21
21
 
22
22
  - **pg-connect**
23
23
  - Connect to a PostgreSQL database
24
- - Input: `connectionString` (string): The PostgreSQL connection string (e.g. postgresql://user:password@host:port/dbname)
24
+ - Inputs:
25
+ - `connectionString` (string): The PostgreSQL connection string without credentials (e.g. postgresql://host:port/dbname or host:port/dbname)
26
+ - `user` (string): The PostgreSQL username
27
+ - `password` (string): The PostgreSQL password
25
28
 
26
29
  - **pg-awr**
27
30
  - Generate a PostgreSQL performance report similar to Oracle AWR. Includes database statistics, top queries (requires pg_stat_statements extension), table/index statistics, connection info, and optimization recommendations.
@@ -35,16 +38,45 @@ The server provides schema information for each table in the database:
35
38
  - Includes column names and data types
36
39
  - Automatically discovered from database metadata
37
40
 
41
+ ## Change Log
42
+
43
+ ### 2025-11-22
44
+ - **feat**: Implement secure PostgreSQL authentication via environment variables and update tool descriptions
45
+ - Added `PG_USER` and `PG_PASSWORD` environment variables for secure credential management
46
+ - Updated `pg-connect` tool to accept explicit user/password arguments
47
+ - Enhanced tool descriptions for better clarity and documentation
48
+
49
+ ### 2025-11-20
50
+ - **feat**: Add initial Postgres server implementation, integrate ModelContextProtocol SDK, and update Oracle tools
51
+ - Complete refactoring of PostgreSQL MCP server
52
+ - Modularized code structure with separate tool handlers
53
+ - Implemented `pg-stats`, `pg-connect`, `pg-explain`, and `pg-awr` tools
54
+ - Renamed query tool to `pg-query` to avoid naming collisions
55
+ - Added Docker image build support for postgres service
56
+
38
57
  ## Configuration
39
58
 
59
+ ### Authentication
60
+
61
+ The PostgreSQL server uses environment variables for secure credential management:
62
+
63
+ - **`PG_USER`**: PostgreSQL username (required)
64
+ - **`PG_PASSWORD`**: PostgreSQL password (required)
65
+
66
+ The connection string should contain only the host, port, and database information (without embedded credentials).
67
+
68
+ **Supported connection string formats:**
69
+ - `postgresql://host:port/dbname`
70
+ - `host:port/dbname`
71
+
40
72
  ### Usage with Claude Desktop
41
73
 
42
74
  To use this server with the Claude Desktop app, add the following configuration to the "mcpServers" section of your `claude_desktop_config.json`:
43
75
 
44
76
  ### Docker
45
77
 
46
- * when running docker on macos, use host.docker.internal if the server is running on the host network (eg localhost)
47
- * username/password can be added to the postgresql url with `postgresql://user:password@host:port/db-name`
78
+ * When running Docker on macOS, use `host.docker.internal` if the PostgreSQL server is running on the host network (e.g., localhost)
79
+ * Credentials are passed via environment variables `PG_USER` and `PG_PASSWORD`
48
80
 
49
81
  ```json
50
82
  {
@@ -54,9 +86,12 @@ To use this server with the Claude Desktop app, add the following configuration
54
86
  "args": [
55
87
  "run",
56
88
  "-i",
57
- "--rm",
89
+ "--rm",
90
+ "-e", "PG_USER=myuser",
91
+ "-e", "PG_PASSWORD=mypassword",
58
92
  "mochoa/mcp-postgres",
59
- "postgresql://host.docker.internal:5432/mydb"]
93
+ "postgresql://host.docker.internal:5432/mydb"
94
+ ]
60
95
  }
61
96
  }
62
97
  }
@@ -72,8 +107,12 @@ To use this server with the Claude Desktop app, add the following configuration
72
107
  "args": [
73
108
  "-y",
74
109
  "@marcelo-ochoa/server-postgres",
75
- "postgresql://localhost/mydb"
76
- ]
110
+ "postgresql://localhost:5432/mydb"
111
+ ],
112
+ "env": {
113
+ "PG_USER": "myuser",
114
+ "PG_PASSWORD": "mypassword"
115
+ }
77
116
  }
78
117
  }
79
118
  }
@@ -81,6 +120,11 @@ To use this server with the Claude Desktop app, add the following configuration
81
120
 
82
121
  Replace `/mydb` with your database name.
83
122
 
123
+ **Note**: Replace the following placeholders with your actual values:
124
+ - `myuser` and `mypassword` with your PostgreSQL credentials
125
+ - `localhost:5432` with your PostgreSQL server host and port
126
+ - `mydb` with your database name
127
+
84
128
  ### Usage with VS Code
85
129
 
86
130
  For quick installation, use one of the one-click install buttons below...
@@ -106,7 +150,18 @@ Optionally, you can add it to a file called `.vscode/mcp.json` in your workspace
106
150
  {
107
151
  "type": "promptString",
108
152
  "id": "pg_url",
109
- "description": "PostgreSQL URL (e.g. postgresql://user:pass@host.docker.internal:5432/mydb)"
153
+ "description": "PostgreSQL URL (e.g. postgresql://host.docker.internal:5432/mydb)"
154
+ },
155
+ {
156
+ "type": "promptString",
157
+ "id": "pg_user",
158
+ "description": "PostgreSQL username"
159
+ },
160
+ {
161
+ "type": "promptString",
162
+ "id": "pg_password",
163
+ "description": "PostgreSQL password",
164
+ "password": true
110
165
  }
111
166
  ],
112
167
  "servers": {
@@ -116,6 +171,8 @@ Optionally, you can add it to a file called `.vscode/mcp.json` in your workspace
116
171
  "run",
117
172
  "-i",
118
173
  "--rm",
174
+ "-e", "PG_USER=${input:pg_user}",
175
+ "-e", "PG_PASSWORD=${input:pg_password}",
119
176
  "mochoa/mcp-postgres",
120
177
  "${input:pg_url}"
121
178
  ]
@@ -134,7 +191,18 @@ Optionally, you can add it to a file called `.vscode/mcp.json` in your workspace
134
191
  {
135
192
  "type": "promptString",
136
193
  "id": "pg_url",
137
- "description": "PostgreSQL URL (e.g. postgresql://user:pass@localhost:5432/mydb)"
194
+ "description": "PostgreSQL URL (e.g. postgresql://localhost:5432/mydb)"
195
+ },
196
+ {
197
+ "type": "promptString",
198
+ "id": "pg_user",
199
+ "description": "PostgreSQL username"
200
+ },
201
+ {
202
+ "type": "promptString",
203
+ "id": "pg_password",
204
+ "description": "PostgreSQL password",
205
+ "password": true
138
206
  }
139
207
  ],
140
208
  "servers": {
@@ -144,7 +212,11 @@ Optionally, you can add it to a file called `.vscode/mcp.json` in your workspace
144
212
  "-y",
145
213
  "@marcelo-ochoa/server-postgres",
146
214
  "${input:pg_url}"
147
- ]
215
+ ],
216
+ "env": {
217
+ "PG_USER": "${input:pg_user}",
218
+ "PG_PASSWORD": "${input:pg_password}"
219
+ }
148
220
  }
149
221
  }
150
222
  }
@@ -159,6 +231,10 @@ Docker:
159
231
  docker build -t mochoa/mcp-postgres -f src/postgres/Dockerfile .
160
232
  ```
161
233
 
234
+ ## Sources
235
+
236
+ As usual the code of this extension is at [GitHub](https://github.com/marcelo-ochoa/servers), feel free to suggest changes and make contributions, note that I am a beginner developer of React and TypeScript so contributions to make this UI better are welcome.
237
+
162
238
  ## License
163
239
 
164
240
  This MCP server is licensed under the MIT License. This means you are free to use, modify, and distribute the software, subject to the terms and conditions of the MIT License. For more details, please see the LICENSE file in the project repository.
package/dist/db.js CHANGED
@@ -2,15 +2,52 @@ import pg from "pg";
2
2
  let pool = undefined;
3
3
  let resourceBaseUrl = undefined;
4
4
  export async function initializePool(connectionString) {
5
+ const dbUser = process.env.PG_USER;
6
+ const dbPassword = process.env.PG_PASSWORD;
7
+ if (!dbUser || !dbPassword) {
8
+ console.error("Error: Environment variables PG_USER and PG_PASSWORD must be set.");
9
+ process.exit(1);
10
+ }
11
+ // Parse the connection string to extract host, port, and database
12
+ // Expected format: postgresql://host:port/dbname or host:port/dbname
13
+ let host;
14
+ let port;
15
+ let database;
16
+ try {
17
+ // Try parsing as URL first
18
+ if (connectionString.startsWith('postgresql://') || connectionString.startsWith('postgres://')) {
19
+ const url = new URL(connectionString);
20
+ host = url.hostname;
21
+ port = url.port ? parseInt(url.port) : 5432;
22
+ database = url.pathname.slice(1); // Remove leading '/'
23
+ }
24
+ else {
25
+ // Parse format: host:port/dbname
26
+ const match = connectionString.match(/^([^:]+):(\d+)\/(.+)$/);
27
+ if (!match) {
28
+ throw new Error("Invalid connection string format. Expected: host:port/dbname or postgresql://host:port/dbname");
29
+ }
30
+ host = match[1];
31
+ port = parseInt(match[2]);
32
+ database = match[3];
33
+ }
34
+ }
35
+ catch (err) {
36
+ console.error("Error parsing connection string:", err);
37
+ process.exit(1);
38
+ }
5
39
  pool = new pg.Pool({
6
- connectionString,
40
+ user: dbUser,
41
+ password: dbPassword,
42
+ host,
43
+ port,
44
+ database,
7
45
  });
8
46
  // Test connection
9
47
  const client = await pool.connect();
10
48
  client.release();
11
- const url = new URL(connectionString);
12
- url.protocol = "postgres:";
13
- url.password = "";
49
+ // Build resource base URL without credentials
50
+ const url = new URL(`postgresql://${host}:${port}/${database}`);
14
51
  resourceBaseUrl = url;
15
52
  }
16
53
  export function getPool() {
package/dist/server.js CHANGED
@@ -6,7 +6,7 @@ import { listResourcesHandler, readResourceHandler, callToolHandler } from "./ha
6
6
  import { tools } from "./tools.js";
7
7
  const server = new Server({
8
8
  name: "postgres-server",
9
- version: "0.6.2",
9
+ version: "0.6.3",
10
10
  }, {
11
11
  capabilities: {
12
12
  resources: {},
@@ -1,17 +1,24 @@
1
1
  import { initializePool, closePool } from "../db.js";
2
2
  export const connectHandler = async (request) => {
3
- const connectionString = request.params.arguments?.connectionString;
4
- if (typeof connectionString !== "string" || !connectionString) {
3
+ const newConnectionString = request.params.arguments?.connectionString;
4
+ const newUser = request.params.arguments?.user;
5
+ const newPassword = request.params.arguments?.password;
6
+ if (typeof newConnectionString !== "string" || !newConnectionString ||
7
+ typeof newUser !== "string" || !newUser ||
8
+ typeof newPassword !== "string" || !newPassword) {
5
9
  return {
6
- content: [{ type: "text", text: "Missing or invalid connectionString argument." }],
10
+ content: [{ type: "text", text: "Missing or invalid connectionString, user, or password argument." }],
7
11
  isError: true,
8
12
  };
9
13
  }
10
14
  try {
11
15
  await closePool();
12
- await initializePool(connectionString);
16
+ // Override env vars for this session
17
+ process.env.PG_USER = newUser;
18
+ process.env.PG_PASSWORD = newPassword;
19
+ await initializePool(newConnectionString);
13
20
  return {
14
- content: [{ type: "text", text: `Successfully connected to Postgres DB: ${connectionString}` }],
21
+ content: [{ type: "text", text: `Successfully connected to Postgres DB: ${newConnectionString} as user ${newUser}` }],
15
22
  isError: false,
16
23
  };
17
24
  }
package/dist/tools.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export const tools = [
2
2
  {
3
3
  name: "pg-query",
4
- description: "Run a read-only SQL query",
4
+ description: "This tool executes SQL queries in a READ ONLY session connected to a PostgreSQL database. If no active connection exists, it uses MCP server registration argument and environment variables PG_USER and PG_PASSWORD.\n\nYou should:\n\n\tExecute the provided SQL query.\n\n\tReturn the results in Toon format.\n\nArgs:\n\n\tsql: The SQL query to execute.\n\n\nThe `model` argument should specify only the name and version of the LLM (Large Language Model) you are using, with no additional information.\nThe `mcp_client` argument should specify only the name of the MCP (Model Context Protocol) client you are using, with no additional information.\n\nReturns:\n\n\tJson-formatted query results.\nFor every SQL query you generate, please include a comment at the beginning of the SELECT statement (or other main SQL command) that identifies the LLM model name and version you are using. Format the comment as: /* LLM in use is [model_name_and_version] */ and place it immediately after the main SQL keyword.\nFor example:\n\nSELECT /* LLM in use is claude-sonnet-4 */ column1, column2 FROM table_name;\n\nPlease apply this format consistently to all SQL queries you generate, using your actual model name and version in the comment\n",
5
5
  inputSchema: {
6
6
  type: "object",
7
7
  properties: {
@@ -25,7 +25,7 @@ export const tools = [
25
25
  },
26
26
  {
27
27
  name: "pg-stats",
28
- description: "Get statistics for a specific table",
28
+ description: "Get comprehensive statistics for a specific PostgreSQL table. This tool retrieves detailed information including row counts, table size, index information, column statistics, and other metadata that can help optimize queries and understand data distribution.\n\nArgs:\n\n\tname: The name of the table to get statistics for.\n\n\nThe `model` argument should specify only the name and version of the LLM (Large Language Model) you are using, with no additional information.\nThe `mcp_client` argument should specify only the name of the MCP (Model Context Protocol) client you are using, with no additional information.\n\nReturns:\n\n\tJson-formatted table statistics including row counts, size information, indexes, and column details.\n",
29
29
  inputSchema: {
30
30
  type: "object",
31
31
  properties: {
@@ -49,7 +49,7 @@ export const tools = [
49
49
  },
50
50
  {
51
51
  name: "pg-explain",
52
- description: "Explain Plan for a given SQL query",
52
+ description: "Generate and display the execution plan for a given SQL query using PostgreSQL's EXPLAIN command. This tool helps you understand how PostgreSQL will execute your query, including information about table scans, joins, indexes used, and estimated costs.\n\nArgs:\n\n\tsql: The SQL query to explain.\n\n\nThe `model` argument should specify only the name and version of the LLM (Large Language Model) you are using, with no additional information.\nThe `mcp_client` argument should specify only the name of the MCP (Model Context Protocol) client you are using, with no additional information.\n\nReturns:\n\n\tDetailed execution plan showing how PostgreSQL will process the query, including costs, row estimates, and access methods.\n",
53
53
  inputSchema: {
54
54
  type: "object",
55
55
  properties: {
@@ -73,13 +73,21 @@ export const tools = [
73
73
  },
74
74
  {
75
75
  name: "pg-connect",
76
- description: "Connect to a PostgreSQL database",
76
+ description: "Provides an interface to connect to a specified PostgreSQL database. If a database connection is already active, the tool will close the existing connection before establishing a new one.\n\nThis tool accepts three required parameters:\n\n\tconnectionString: The PostgreSQL connection string without embedded credentials (e.g., postgresql://host:port/dbname or host:port/dbname)\n\tuser: The PostgreSQL username\n\tpassword: The PostgreSQL password\n\nThe credentials are stored in environment variables PG_USER and PG_PASSWORD for the session.\n\nThe `model` argument should only be used to specify the name and version of the LLM (Large Language Model) you are using, with no additional information.\nThe `mcp_client` argument should specify only the name of the MCP (Model Context Protocol) client you are using, with no additional information.\n",
77
77
  inputSchema: {
78
78
  type: "object",
79
79
  properties: {
80
80
  connectionString: {
81
81
  type: "string",
82
- description: "The PostgreSQL connection string (e.g. postgresql://user:password@host:port/dbname)"
82
+ description: "The PostgreSQL connection string (e.g. postgresql://host:port/dbname or host:port/dbname)"
83
+ },
84
+ user: {
85
+ type: "string",
86
+ description: "The PostgreSQL user (e.g. postgres)"
87
+ },
88
+ password: {
89
+ type: "string",
90
+ description: "The PostgreSQL password"
83
91
  },
84
92
  mcp_client: {
85
93
  "type": "string",
@@ -92,7 +100,7 @@ export const tools = [
92
100
  "default": "UNKNOWN-LLM"
93
101
  }
94
102
  },
95
- required: ["connectionString"]
103
+ required: ["connectionString", "user", "password"]
96
104
  },
97
105
  },
98
106
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marcelo-ochoa/server-postgres",
3
- "version": "0.6.2",
3
+ "version": "0.6.3",
4
4
  "description": "MCP server for interacting with PostgreSQL databases",
5
5
  "keywords": [
6
6
  "read-only-mcp",