/**
* postgres-mcp - CLI Arguments Parser
*
* Command-line argument parsing for the PostgreSQL MCP server.
*/
import type { TransportType, DatabaseConfig, OAuthConfig } from '../types/index.js';
/**
* Parsed CLI configuration
*/
export interface ParsedArgs {
/** Server transport type */
transport: TransportType;
/** HTTP port (for http/sse transports) */
port?: number;
/** Database configuration */
database?: DatabaseConfig;
/** OAuth configuration */
oauth?: OAuthConfig;
/** Tool filter string */
toolFilter?: string;
/** Log level */
logLevel?: 'debug' | 'info' | 'notice' | 'warning' | 'error' | 'critical' | 'alert' | 'emergency';
/** Whether to exit after printing help/version */
shouldExit: boolean;
}
const VERSION = '0.1.0';
/**
* Parse command line arguments
*/
export function parseArgs(argv: string[] = process.argv.slice(2)): ParsedArgs {
const result: ParsedArgs = {
transport: 'stdio',
shouldExit: false
};
// OAuth config accumulator
let oauthEnabled = false;
let oauthIssuer: string | undefined;
let oauthAudience: string | undefined;
let oauthJwksUri: string | undefined;
let oauthClockTolerance: number | undefined;
// Database config accumulator
let pgConnectionString: string | undefined;
let pgHost: string | undefined;
let pgPort: number | undefined;
let pgUser: string | undefined;
let pgPassword: string | undefined;
let pgDatabase: string | undefined;
let pgSsl = false;
let poolMax: number | undefined;
for (let i = 0; i < argv.length; i++) {
const arg = argv[i];
const nextArg = argv[i + 1];
switch (arg) {
// Transport options
case '--transport':
case '-t':
if (nextArg && !nextArg.startsWith('-')) {
result.transport = nextArg as TransportType;
i++;
}
break;
case '--port':
case '-p':
if (nextArg && !nextArg.startsWith('-')) {
result.port = parseInt(nextArg, 10);
i++;
}
break;
// PostgreSQL connection options
case '--postgres':
if (nextArg && !nextArg.startsWith('-')) {
pgConnectionString = nextArg;
i++;
}
break;
case '--host':
if (nextArg && !nextArg.startsWith('-')) {
pgHost = nextArg;
i++;
}
break;
case '--pg-port':
if (nextArg && !nextArg.startsWith('-')) {
pgPort = parseInt(nextArg, 10);
i++;
}
break;
case '--user':
if (nextArg && !nextArg.startsWith('-')) {
pgUser = nextArg;
i++;
}
break;
case '--password':
if (nextArg && !nextArg.startsWith('-')) {
pgPassword = nextArg;
i++;
}
break;
case '--database':
if (nextArg && !nextArg.startsWith('-')) {
pgDatabase = nextArg;
i++;
}
break;
case '--ssl':
pgSsl = true;
break;
case '--pool-max':
if (nextArg && !nextArg.startsWith('-')) {
poolMax = parseInt(nextArg, 10);
i++;
}
break;
// Tool filter
case '--tool-filter':
case '-f':
// Note: tool filter values can start with '-' (e.g., "-base,-extensions,+starter")
if (nextArg !== undefined) {
result.toolFilter = nextArg;
i++;
}
break;
// Log level
case '--log-level':
if (nextArg && !nextArg.startsWith('-')) {
result.logLevel = nextArg as 'debug' | 'info' | 'notice' | 'warning' | 'error' | 'critical' | 'alert' | 'emergency';
i++;
}
break;
// OAuth options
case '--oauth-enabled':
case '-o':
oauthEnabled = true;
break;
case '--oauth-issuer':
if (nextArg && !nextArg.startsWith('-')) {
oauthIssuer = nextArg;
i++;
}
break;
case '--oauth-audience':
if (nextArg && !nextArg.startsWith('-')) {
oauthAudience = nextArg;
i++;
}
break;
case '--oauth-jwks-uri':
if (nextArg && !nextArg.startsWith('-')) {
oauthJwksUri = nextArg;
i++;
}
break;
case '--oauth-clock-tolerance':
if (nextArg && !nextArg.startsWith('-')) {
oauthClockTolerance = parseInt(nextArg, 10);
i++;
}
break;
// Help and version
case '--version':
case '-v':
console.error(`postgres-mcp version ${VERSION}`);
result.shouldExit = true;
return result;
case '--help':
case '-h':
printHelp();
result.shouldExit = true;
return result;
default:
if (arg?.startsWith('-')) {
console.error(`Unknown option: ${arg}`);
printHelp();
process.exit(1);
}
}
}
// Build database config from connection string or individual params
if (pgConnectionString) {
result.database = parseConnectionString(pgConnectionString, poolMax);
} else {
// Check individual params or environment variables
const host = pgHost ?? process.env['PGHOST'] ?? process.env['POSTGRES_HOST'];
const port = pgPort ?? parseInt(process.env['PGPORT'] ?? process.env['POSTGRES_PORT'] ?? '5432', 10);
const user = pgUser ?? process.env['PGUSER'] ?? process.env['POSTGRES_USER'];
const password = pgPassword ?? process.env['PGPASSWORD'] ?? process.env['POSTGRES_PASSWORD'];
const database = pgDatabase ?? process.env['PGDATABASE'] ?? process.env['POSTGRES_DATABASE'];
if (host || user || database) {
const dbConfig: DatabaseConfig = {
type: 'postgresql',
host: host ?? 'localhost',
port,
username: user ?? 'postgres',
database: database ?? 'postgres'
};
if (password) dbConfig.password = password;
if (poolMax !== undefined && poolMax > 0) dbConfig.pool = { max: poolMax };
if (pgSsl) dbConfig.options = { ssl: true };
result.database = dbConfig;
}
}
// Check for tool filter in environment
const envToolFilter = process.env['POSTGRES_TOOL_FILTER'] ?? process.env['MCP_TOOL_FILTER'];
if (envToolFilter) {
result.toolFilter ??= envToolFilter;
}
// Check for log level in environment
if (!result.logLevel && process.env['LOG_LEVEL']) {
result.logLevel = process.env['LOG_LEVEL'] as 'debug' | 'info' | 'notice' | 'warning' | 'error' | 'critical' | 'alert' | 'emergency';
}
// Check OAuth environment variables
if (!oauthEnabled && process.env['OAUTH_ENABLED'] === 'true') {
oauthEnabled = true;
}
oauthIssuer ??= process.env['OAUTH_ISSUER'];
oauthAudience ??= process.env['OAUTH_AUDIENCE'];
oauthJwksUri ??= process.env['OAUTH_JWKS_URI'];
if (oauthClockTolerance === undefined && process.env['OAUTH_CLOCK_TOLERANCE']) {
oauthClockTolerance = parseInt(process.env['OAUTH_CLOCK_TOLERANCE'], 10);
}
// Build OAuth config if enabled
if (oauthEnabled) {
const oauth: OAuthConfig = {
enabled: true
};
if (oauthIssuer) oauth.authorizationServerUrl = oauthIssuer;
if (oauthIssuer) oauth.issuer = oauthIssuer;
if (oauthAudience) oauth.audience = oauthAudience;
if (oauthJwksUri) oauth.jwksUri = oauthJwksUri;
if (oauthClockTolerance !== undefined) oauth.clockTolerance = oauthClockTolerance;
result.oauth = oauth;
}
return result;
}
/**
* Parse PostgreSQL connection string
*/
function parseConnectionString(connectionString: string, poolMax?: number): DatabaseConfig {
const url = new URL(connectionString);
const config: DatabaseConfig = {
type: 'postgresql',
host: url.hostname || 'localhost',
port: parseInt(url.port, 10) || 5432,
username: url.username || 'postgres',
database: url.pathname.slice(1) || 'postgres'
};
if (url.password) config.password = url.password;
// Check for SSL in query params
if (url.searchParams.get('ssl') === 'true' || url.searchParams.get('sslmode') === 'require') {
config.options = { ssl: true };
}
// Pool configuration
if (poolMax !== undefined && poolMax > 0) {
config.pool = { max: poolMax };
}
return config;
}
/**
* Print help message
*/
export function printHelp(): void {
console.error(`
postgres-mcp - PostgreSQL MCP Server
Usage: postgres-mcp [options]
Connection Options:
--postgres <url> PostgreSQL connection string
(postgres://user:pass@host:port/database)
--host <host> PostgreSQL host (default: localhost)
--pg-port <port> PostgreSQL port (default: 5432)
--user <user> PostgreSQL username (default: postgres)
--password <pass> PostgreSQL password
--database <db> PostgreSQL database name (default: postgres)
--ssl Enable SSL connection
--pool-max <n> Maximum pool connections (default: 10)
Server Options:
--transport, -t <type> Transport type: stdio, http, sse (default: stdio)
--port, -p <port> HTTP port for http/sse transports (default: 3000)
--tool-filter, -f <str> Tool filter string (e.g., "-base,-extensions,+starter")
--log-level <level> Log level: debug, info, notice, warning, error, critical, alert, emergency
OAuth Options:
--oauth-enabled, -o Enable OAuth 2.0 authentication
--oauth-issuer <url> Authorization server URL (issuer)
--oauth-audience <aud> Expected token audience
--oauth-jwks-uri <url> JWKS URI (auto-discovered from issuer if not set)
--oauth-clock-tolerance Clock tolerance in seconds (default: 60)
Other:
--version, -v Show version
--help, -h Show this help
Environment Variables:
PGHOST, POSTGRES_HOST PostgreSQL host
PGPORT, POSTGRES_PORT PostgreSQL port
PGUSER, POSTGRES_USER PostgreSQL username
PGPASSWORD, POSTGRES_PASSWORD PostgreSQL password
PGDATABASE, POSTGRES_DATABASE PostgreSQL database
POSTGRES_TOOL_FILTER Tool filter string
LOG_LEVEL Log level (debug, info, notice, warning, error, critical, alert, emergency)
OAUTH_ENABLED Enable OAuth (true/false)
OAUTH_ISSUER Authorization server URL
OAUTH_AUDIENCE Expected token audience
OAUTH_JWKS_URI JWKS endpoint URL
OAUTH_CLOCK_TOLERANCE Clock tolerance in seconds
`);
}