Opik MCP Server
Official
by comet-ml
- src
/**
* Configuration loader for Opik MCP server
* Loads and validates environment variables from .env file
* and/or command-line arguments
*/
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import * as fs from 'node:fs';
/**
* File-based logger
* Only writes if debug mode is enabled or being set to enabled
*/
function writeToLogFile(message: string, forceWrite: boolean = false): void {
try {
// Check if debug mode is enabled or being set to enabled
// This check is special because we're in the process of parsing args
const debugArg =
process.argv.includes('--debug') &&
process.argv[process.argv.indexOf('--debug') + 1] === 'true';
const debugEnv = process.env.DEBUG_MODE === 'true';
if (debugArg || debugEnv || forceWrite) {
const logFile = '/tmp/opik-mcp.log';
if (!fs.existsSync(logFile)) {
fs.writeFileSync(logFile, `Opik MCP Server Started: ${new Date().toISOString()}\n`);
}
fs.appendFileSync(logFile, `[${new Date().toISOString()}] [config] ${message}\n`);
}
} catch (error) {
// Silently fail if we can't write to the log file
}
}
interface OpikConfig {
// API configuration
apiBaseUrl: string;
workspaceName?: string; // Optional for self-hosted version
apiKey: string;
isSelfHosted: boolean;
debugMode: boolean;
// Transport configuration
transport: 'stdio' | 'sse';
ssePort?: number;
sseHost?: string;
sseLogPath?: string;
// MCP server configuration
mcpName: string;
mcpVersion: string;
mcpPort?: number;
mcpLogging: boolean;
mcpDefaultWorkspace: string;
mcpEnablePromptTools: boolean;
mcpEnableProjectTools: boolean;
mcpEnableTraceTools: boolean;
mcpEnableMetricTools: boolean;
}
/**
* Parse command-line arguments
*/
function parseCommandLineArgs() {
return (
yargs(hideBin(process.argv))
// API Configuration
.option('apiUrl', {
alias: 'url',
type: 'string',
description: 'API base URL',
})
.option('apiKey', {
alias: 'key',
type: 'string',
description: 'API key for authentication',
})
.option('workspace', {
alias: 'ws',
type: 'string',
description: 'Workspace name',
})
.option('selfHosted', {
type: 'boolean',
description: 'Whether the instance is self-hosted',
})
.option('debug', {
type: 'boolean',
description: 'Enable debug mode',
})
// Transport Configuration
.option('transport', {
type: 'string',
description: 'Transport type (stdio or sse)',
choices: ['stdio', 'sse'],
default: 'stdio',
})
.option('ssePort', {
type: 'number',
description: 'Port for SSE transport',
default: 3001,
})
.option('sseHost', {
type: 'string',
description: 'Host for SSE transport',
default: 'localhost',
})
.option('sseLogPath', {
type: 'string',
description: 'Log file path for SSE transport',
default: '/tmp/opik-mcp-sse.log',
})
// MCP Configuration
.option('mcpName', {
type: 'string',
description: 'MCP server name',
})
.option('mcpVersion', {
type: 'string',
description: 'MCP server version',
})
.option('mcpPort', {
type: 'number',
description: 'MCP server port',
})
.option('mcpLogging', {
type: 'boolean',
description: 'Enable MCP server logging',
})
.option('mcpDefaultWorkspace', {
type: 'string',
description: 'Default workspace name',
})
// Tool enablement
.option('disablePromptTools', {
type: 'boolean',
description: 'Disable prompt-related tools',
})
.option('disableProjectTools', {
type: 'boolean',
description: 'Disable project-related tools',
})
.option('disableTraceTools', {
type: 'boolean',
description: 'Disable trace-related tools',
})
.option('disableMetricTools', {
type: 'boolean',
description: 'Disable metric-related tools',
})
.help()
.parse() as {
apiUrl?: string;
apiKey?: string;
workspace?: string;
selfHosted?: boolean;
debug?: boolean;
transport?: string;
ssePort?: number;
sseHost?: string;
sseLogPath?: string;
mcpName?: string;
mcpVersion?: string;
mcpPort?: number;
mcpLogging?: boolean;
mcpDefaultWorkspace?: string;
disablePromptTools?: boolean;
disableProjectTools?: boolean;
disableTraceTools?: boolean;
disableMetricTools?: boolean;
[key: string]: unknown;
}
);
}
/**
* Load environment variables with fallbacks
*/
function loadConfig(): OpikConfig {
// Parse command-line arguments first
const args = parseCommandLineArgs();
// Try to load from process.env and command-line args, with command-line taking precedence
const config: OpikConfig = {
// API configuration with fallbacks - with much more forgiving defaults
apiBaseUrl: args.apiUrl || process.env.OPIK_API_BASE_URL || 'https://www.comet.com/opik/api',
workspaceName: (args.workspace || process.env.OPIK_WORKSPACE_NAME || 'default').replace(
/^['"](.*)['"]$/,
'$1'
), // Remove any quotes
apiKey: args.apiKey || process.env.OPIK_API_KEY || '',
isSelfHosted:
args.selfHosted !== undefined
? args.selfHosted
: process.env.OPIK_SELF_HOSTED === 'true' || false,
debugMode: args.debug !== undefined ? args.debug : process.env.DEBUG_MODE === 'true' || false,
// Transport configuration
transport: (args.transport || process.env.TRANSPORT || 'stdio') as 'stdio' | 'sse',
ssePort: args.ssePort || (process.env.SSE_PORT ? parseInt(process.env.SSE_PORT, 10) : 3001),
sseHost: args.sseHost || process.env.SSE_HOST || 'localhost',
sseLogPath: args.sseLogPath || process.env.SSE_LOG_PATH || '/tmp/opik-mcp-sse.log',
// MCP configuration with fallbacks
mcpName: args.mcpName || process.env.MCP_NAME || 'opik-manager',
mcpVersion: args.mcpVersion || process.env.MCP_VERSION || '1.0.0',
mcpPort:
args.mcpPort || (process.env.MCP_PORT ? parseInt(process.env.MCP_PORT, 10) : undefined),
mcpLogging:
args.mcpLogging !== undefined ? args.mcpLogging : process.env.MCP_LOGGING === 'true' || false,
mcpDefaultWorkspace: args.mcpDefaultWorkspace || process.env.MCP_DEFAULT_WORKSPACE || 'default',
// Tool enablement with fallbacks - note the logic reversal for the command-line args
mcpEnablePromptTools: args.disablePromptTools
? false
: process.env.MCP_ENABLE_PROMPT_TOOLS !== 'false', // Enable by default
mcpEnableProjectTools: args.disableProjectTools
? false
: process.env.MCP_ENABLE_PROJECT_TOOLS !== 'false', // Enable by default
mcpEnableTraceTools: args.disableTraceTools
? false
: process.env.MCP_ENABLE_TRACE_TOOLS !== 'false', // Enable by default
mcpEnableMetricTools: args.disableMetricTools
? false
: process.env.MCP_ENABLE_METRIC_TOOLS !== 'false', // Enable by default
};
// Validate required fields but be much more forgiving
if (!config.apiKey) {
// Only warn about missing API key, don't throw an error
writeToLogFile(`Warning: No API key provided - some functionality will be limited`, true);
// Still allow the server to start even without an API key
}
// Log configuration if in debug mode
if (config.debugMode) {
writeToLogFile('Opik MCP Configuration:');
writeToLogFile(`- API Base URL: ${config.apiBaseUrl}`);
writeToLogFile(`- Self-hosted: ${config.isSelfHosted ? 'Yes' : 'No'}`);
if (!config.isSelfHosted) {
writeToLogFile(`- Workspace: ${config.workspaceName}`);
}
writeToLogFile(`- Debug mode: ${config.debugMode ? 'Enabled' : 'Disabled'}`);
// Log transport configuration
writeToLogFile('\nTransport Configuration:');
writeToLogFile(`- Transport: ${config.transport}`);
if (config.transport === 'sse') {
writeToLogFile(`- SSE Port: ${config.ssePort}`);
writeToLogFile(`- SSE Host: ${config.sseHost}`);
writeToLogFile(`- SSE Log Path: ${config.sseLogPath}`);
}
// Log MCP configuration
writeToLogFile('\nMCP Configuration:');
writeToLogFile(`- MCP Name: ${config.mcpName}`);
writeToLogFile(`- MCP Version: ${config.mcpVersion}`);
if (config.mcpPort) writeToLogFile(`- MCP Port: ${config.mcpPort}`);
writeToLogFile(`- MCP Logging: ${config.mcpLogging ? 'Enabled' : 'Disabled'}`);
writeToLogFile(`- MCP Default Workspace: ${config.mcpDefaultWorkspace}`);
writeToLogFile(`- Prompt Tools: ${config.mcpEnablePromptTools ? 'Enabled' : 'Disabled'}`);
writeToLogFile(`- Project Tools: ${config.mcpEnableProjectTools ? 'Enabled' : 'Disabled'}`);
writeToLogFile(`- Trace Tools: ${config.mcpEnableTraceTools ? 'Enabled' : 'Disabled'}`);
writeToLogFile(`- Metric Tools: ${config.mcpEnableMetricTools ? 'Enabled' : 'Disabled'}`);
}
return config;
}
// Export the configuration
const config = loadConfig();
export default config;