postgres-mcp-tools
Version:
PostgreSQL-based memory system with vector search capabilities for AI applications, including MCP integration for Claude
122 lines (121 loc) • 3.26 kB
JavaScript
import pkg from 'pg';
const { Pool } = pkg;
import dotenv from 'dotenv';
import { logger } from '../utils/logger.js';
// Load environment variables
dotenv.config();
// Database connection configuration
const poolConfig = {
user: process.env.POSTGRES_USER || 'memory_user',
host: process.env.POSTGRES_HOST || 'localhost',
database: process.env.POSTGRES_DB || 'memory_db',
password: process.env.POSTGRES_PASSWORD,
port: parseInt(process.env.POSTGRES_PORT || '5432', 10),
max: parseInt(process.env.PG_MAX_CONNECTIONS || '20', 10),
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000,
ssl: process.env.POSTGRES_SSL === 'true' ? { rejectUnauthorized: false } : false,
};
// Create a connection pool
const pool = new Pool(poolConfig);
// Pool error handler
pool.on('error', (err) => {
logger.error('Unexpected error on idle client', err);
process.exit(-1);
});
/**
* Get a client from the pool
* @returns A database client
*/
export const getClient = async () => {
try {
const client = await pool.connect();
return client;
}
catch (error) {
logger.error('Error connecting to database', error);
throw error;
}
};
/**
* Execute a query on the database
* @param text The SQL query
* @param params The query parameters
* @returns The query result
*/
export const query = async (text, params) => {
const start = Date.now();
try {
const res = await pool.query(text, params);
const duration = Date.now() - start;
// Log slow queries for optimization
if (duration > 100) {
logger.warn(`Slow query (${duration}ms): ${text}`);
}
return res;
}
catch (error) {
logger.error(`Query error: ${error.message}`, {
query: text,
params,
error: error.stack,
});
throw error;
}
};
/**
* Execute a transaction on the database
* @param callback The callback function to execute within the transaction
* @returns The result of the callback
*/
export const transaction = async (callback) => {
const client = await getClient();
try {
await client.query('BEGIN');
const result = await callback(client);
await client.query('COMMIT');
return result;
}
catch (error) {
await client.query('ROLLBACK');
logger.error('Transaction error:', error);
throw error;
}
finally {
client.release();
}
};
/**
* Check the health of the database connection
* @returns True if the database is healthy, false otherwise
*/
export const healthCheck = async () => {
try {
const result = await query('SELECT NOW()');
return result.rows[0] ? true : false;
}
catch (error) {
logger.error('Database health check failed', error);
return false;
}
};
/**
* Close the database connection pool
*/
export const closePool = async () => {
try {
await pool.end();
logger.info('Database pool closed');
}
catch (error) {
logger.error('Error closing database pool', error);
throw error;
}
};
export default {
query,
getClient,
transaction,
healthCheck,
closePool,
};