import { findConfigPath, parseConfig as parseTransportConfig } from '@mcp-z/server';
import * as fs from 'fs';
import moduleRoot from 'module-root-sync';
import { homedir } from 'os';
import * as path from 'path';
import * as url from 'url';
import { parseArgs } from 'util';
import type { ServerConfig } from '../types.ts';
const pkg = JSON.parse(fs.readFileSync(path.join(moduleRoot(url.fileURLToPath(import.meta.url)), 'package.json'), 'utf-8'));
const HELP_TEXT = `
Usage: mcp-pdf [options]
MCP server for PDF document generation and processing.
Options:
--version Show version number
--help Show this help message
--base-url=<url> Base URL for HTTP file serving
--log-level=<level> Logging level (default: info)
--resource-store-uri=<uri> Resource store URI for file storage (default: file://~/.mcp-z/mcp-pdf/files)
Environment Variables:
BASE_URL Base URL for HTTP file serving (optional)
LOG_LEVEL Default logging level (optional)
RESOURCE_STORE_URI Resource store URI (optional, file://)
Examples:
mcp-pdf # Use default settings
mcp-pdf --port=3000 # HTTP transport on port 3000
mcp-pdf --resource-store-uri=file:///tmp/pdfs # Custom resource store URI
LOG_LEVEL=debug mcp-pdf # Set log level via env var
`.trim();
/**
* Handle --version and --help flags before config parsing.
* These should work without requiring any configuration.
*/
export function handleVersionHelp(args: string[]): { handled: boolean; output?: string } {
const { values } = parseArgs({
args,
options: {
version: { type: 'boolean' },
help: { type: 'boolean' },
},
strict: false,
});
if (values.version) return { handled: true, output: pkg.version };
if (values.help) return { handled: true, output: HELP_TEXT };
return { handled: false };
}
/**
* Parse PDF server configuration from CLI arguments and environment.
*/
export function parseConfig(args: string[], env: Record<string, string | undefined>): ServerConfig {
const transportConfig = parseTransportConfig(args, env);
// Parse application-level config (LOG_LEVEL, RESOURCE_STORE_URI, BASE_URL)
const { values } = parseArgs({
args,
options: {
'log-level': { type: 'string' },
'base-url': { type: 'string' },
'resource-store-uri': { type: 'string' },
},
strict: false, // Allow other arguments
allowPositionals: true,
});
const name = pkg.name.replace(/^@[^/]+\//, '');
let rootDir = homedir();
try {
const configPath = findConfigPath({ config: '.mcp.json', cwd: process.cwd(), stopDir: homedir() });
rootDir = path.dirname(configPath);
} catch {
rootDir = homedir();
}
const baseDir = path.join(rootDir, '.mcp-z');
const cliBaseUrl = typeof values['base-url'] === 'string' ? values['base-url'] : undefined;
const envBaseUrl = env.BASE_URL;
const baseUrl = cliBaseUrl ?? envBaseUrl;
const cliLogLevel = typeof values['log-level'] === 'string' ? values['log-level'] : undefined;
const envLogLevel = env.LOG_LEVEL;
const logLevel = cliLogLevel ?? envLogLevel ?? 'info';
// Parse file storage configuration
const cliResourceStoreUri = typeof values['resource-store-uri'] === 'string' ? values['resource-store-uri'] : undefined;
const envResourceStoreUri = env.RESOURCE_STORE_URI;
const defaultResourceStorePath = path.join(baseDir, name, 'files');
const resourceStoreUri = normalizeResourceStoreUri(cliResourceStoreUri ?? envResourceStoreUri ?? defaultResourceStorePath);
// Combine configs
return {
...transportConfig,
resourceStoreUri,
...(baseUrl && { baseUrl }),
logLevel,
baseDir,
name,
version: pkg.version,
};
}
/**
* Build production configuration from process globals.
* Entry point for production server.
*/
export function createConfig(): ServerConfig {
return parseConfig(process.argv, process.env);
}
function normalizeResourceStoreUri(resourceStoreUri: string): string {
const filePrefix = 'file://';
if (resourceStoreUri.startsWith(filePrefix)) {
const rawPath = resourceStoreUri.slice(filePrefix.length);
const expandedPath = rawPath.startsWith('~') ? rawPath.replace(/^~/, homedir()) : rawPath;
return `${filePrefix}${path.resolve(expandedPath)}`;
}
if (resourceStoreUri.includes('://')) return resourceStoreUri;
const expandedPath = resourceStoreUri.startsWith('~') ? resourceStoreUri.replace(/^~/, homedir()) : resourceStoreUri;
return `${filePrefix}${path.resolve(expandedPath)}`;
}