@scarlet-mesh/mcp-products
Version:
Comprehensive Red Hat Product Lifecycle Management MCP Server with advanced features for roadmap analysis, migration planning, compliance reporting, portfolio optimization, and cost analysis
768 lines (767 loc) • 30.5 kB
JavaScript
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { z } from 'zod';
// Create server instance
const server = new McpServer({
name: 'product-lifecycle-api',
version: '1.0.0',
capabilities: {
resources: {},
tools: {},
},
});
const productData = await fetch(`https://access.redhat.com/product-life-cycles/api/v1/products/`)
.then((res) => res.json())
.then((data) => data.data);
// Helper function to load product data
function loadProductData() {
// Sample data - replace with your full dataset
return productData;
}
// Helper function to get product by name
function getProductByName(name) {
const products = loadProductData();
return (products.find((p) => p.name.toLowerCase() === name.toLowerCase() ||
p.former_names.some((fn) => fn.toLowerCase() === name.toLowerCase())) || null);
}
// Helper function to format dates nicely
function formatDate(dateString) {
const date = new Date(dateString);
return date.toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric',
});
}
// Helper function to determine product status based on dates
function getLifecycleStatus(version) {
const now = new Date();
// Find GA date
const gaPhase = version.phases.find((p) => p.name === 'General availability');
if (!gaPhase || new Date(gaPhase.date) > now) {
return 'Future Release';
}
// Find EOL date
const eolPhase = version.phases.find((p) => p.name === 'End of Life');
if (eolPhase && new Date(eolPhase.date) <= now) {
return 'End of Life';
}
// Find Full Support end date
const fullSupportPhase = version.phases.find((p) => p.name === 'Full support');
if (fullSupportPhase && new Date(fullSupportPhase.date) <= now) {
return 'Maintenance Support';
}
return 'Full Support';
}
// Helper function to get time remaining in current phase
function getTimeRemaining(version) {
const now = new Date();
const status = getLifecycleStatus(version);
if (status === 'End of Life') {
return 'No support remaining';
}
if (status === 'Future Release') {
const gaPhase = version.phases.find((p) => p.name === 'General availability');
if (gaPhase) {
const gaDate = new Date(gaPhase.date);
const daysUntilGA = Math.ceil((gaDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
return `${daysUntilGA} days until General Availability`;
}
return 'Release date undetermined';
}
// For Full Support or Maintenance Support, calculate time to next phase
const nextPhase = status === 'Full Support'
? version.phases.find((p) => p.name === 'Full support')
: version.phases.find((p) => p.name === 'End of Life');
if (nextPhase) {
const nextDate = new Date(nextPhase.date);
const daysRemaining = Math.ceil((nextDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
return `${daysRemaining} days remaining`;
}
return 'Unknown';
}
// Register tool: Get all products
server.tool('get-all-products', 'Get a list of all available products', {}, async () => {
const products = loadProductData();
if (!products || products.length === 0) {
return {
content: [
{
type: 'text',
text: 'No product data available.',
},
],
};
}
const productNames = products.map((p) => p.name).join(', ');
return {
content: [
{
type: 'text',
text: `Available products: ${productNames}`,
},
],
};
});
// Register tool: Get product info by name
server.tool('get-product-info', 'Get detailed information about a specific product', {
productName: z.string().describe('The name of the product to look up'),
}, async ({ productName }) => {
const product = getProductByName(productName);
if (!product) {
return {
content: [
{
type: 'text',
text: `Product "${productName}" not found. Please check the name and try again.`,
},
],
};
}
// Build the response text
const responseLines = [
`# ${product.name} Product Lifecycle Information`,
'',
product.former_names.length > 0
? `Also known as: ${product.former_names.join(', ')}`
: '',
'',
'## Versions',
'',
];
product.versions.forEach((version) => {
const status = getLifecycleStatus(version);
const timeRemaining = getTimeRemaining(version);
responseLines.push(`### ${version.name} (${status})`);
responseLines.push('');
version.phases.forEach((phase) => {
responseLines.push(`- **${phase.name}**: ${formatDate(phase.date)}`);
});
responseLines.push(`- **Current Status**: ${status}`);
responseLines.push(`- **Time Remaining**: ${timeRemaining}`);
responseLines.push('');
});
if (product.footnote) {
responseLines.push(`**Note**: ${product.footnote}`);
responseLines.push('');
}
if (product.link) {
responseLines.push(`For more information, visit: ${product.link}`);
}
return {
content: [
{
type: 'text',
text: responseLines.join('\n'),
},
],
};
});
// Register tool: Find versions by support status
server.tool('find-versions-by-status', 'Find product versions with a specific support status', {
productName: z.string().describe('The name of the product to look up'),
status: z
.enum([
'Full Support',
'Maintenance Support',
'End of Life',
'EOL',
'General Availability',
'GA',
'Future Release',
])
.describe('The support status to filter by'),
}, async ({ productName, status }) => {
const product = getProductByName(productName);
if (!product) {
return {
content: [
{
type: 'text',
text: `Product "${productName}" not found. Please check the name and try again.`,
},
],
};
}
const matchingVersions = product.versions.filter((version) => {
const versionStatus = getLifecycleStatus(version);
return versionStatus === status;
});
if (matchingVersions.length === 0) {
return {
content: [
{
type: 'text',
text: `No versions of ${product.name} with status "${status}" found.`,
},
],
};
}
const responseLines = [
`# ${product.name} Versions with Status: ${status}`,
'',
];
matchingVersions.forEach((version) => {
const timeRemaining = getTimeRemaining(version);
responseLines.push(`## ${version.name}`);
responseLines.push('');
version.phases.forEach((phase) => {
responseLines.push(`- **${phase.name}**: ${formatDate(phase.date)}`);
});
responseLines.push(`- **Time Remaining**: ${timeRemaining}`);
responseLines.push('');
});
return {
content: [
{
type: 'text',
text: responseLines.join('\n'),
},
],
};
});
// Register tool: Find versions expiring within time period
server.tool('find-expiring-versions', 'Find product versions expiring within a specified number of days', {
productName: z.string().describe('The name of the product to look up'),
days: z
.number()
.describe('Number of days to look ahead for expiring versions'),
}, async ({ productName, days }) => {
const product = getProductByName(productName);
if (!product) {
return {
content: [
{
type: 'text',
text: `Product "${productName}" not found. Please check the name and try again.`,
},
],
};
}
const now = new Date();
const futureDate = new Date(now.getTime() + days * 24 * 60 * 60 * 1000);
const expiringVersions = product.versions.filter((version) => {
// Check if Full Support or End of Life phases are within the time window
return version.phases.some((phase) => {
if (phase.name === 'Full support' || phase.name === 'End of Life') {
const phaseDate = new Date(phase.date);
return phaseDate > now && phaseDate <= futureDate;
}
return false;
});
});
if (expiringVersions.length === 0) {
return {
content: [
{
type: 'text',
text: `No versions of ${product.name} are expiring within the next ${days} days.`,
},
],
};
}
const responseLines = [
`# ${product.name} Versions Expiring Within ${days} Days`,
'',
];
expiringVersions.forEach((version) => {
const status = getLifecycleStatus(version);
responseLines.push(`## ${version.name} (Currently: ${status})`);
responseLines.push('');
version.phases.forEach((phase) => {
const phaseDate = new Date(phase.date);
if (phaseDate > now && phaseDate <= futureDate) {
const daysUntil = Math.ceil((phaseDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
responseLines.push(`- **${phase.name}**: ${formatDate(phase.date)} (in ${daysUntil} days)`);
}
else {
responseLines.push(`- **${phase.name}**: ${formatDate(phase.date)}`);
}
});
responseLines.push('');
});
return {
content: [
{
type: 'text',
text: responseLines.join('\n'),
},
],
};
});
// NEW ADVANCED TOOLS START HERE
// Register tool: Product roadmap analysis
server.tool('get-product-roadmap', 'Get a comprehensive roadmap view of all product versions with timeline visualization', {
productName: z.string().describe('The name of the product to analyze'),
timeframeMonths: z.number().optional().describe('Number of months ahead to analyze (default: 24)'),
}, async ({ productName, timeframeMonths = 24 }) => {
const product = getProductByName(productName);
if (!product) {
return {
content: [
{
type: 'text',
text: `Product "${productName}" not found.`,
},
],
};
}
const now = new Date();
const futureDate = new Date();
futureDate.setMonth(futureDate.getMonth() + timeframeMonths);
const roadmapEvents = [];
product.versions.forEach((version) => {
version.phases.forEach((phase) => {
const phaseDate = new Date(phase.date);
if (phaseDate >= now && phaseDate <= futureDate) {
roadmapEvents.push({
version: version.name,
phase: phase.name,
date: phaseDate,
dateString: phase.date,
monthsFromNow: Math.round((phaseDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24 * 30))
});
}
});
});
// Sort by date
roadmapEvents.sort((a, b) => a.date.getTime() - b.date.getTime());
const responseLines = [
`# ${product.name} - Product Roadmap (${timeframeMonths} months)`,
'',
`## Upcoming Lifecycle Events`,
''
];
if (roadmapEvents.length === 0) {
responseLines.push(`No lifecycle events scheduled for the next ${timeframeMonths} months.`);
}
else {
roadmapEvents.forEach((event) => {
responseLines.push(`### ${formatDate(event.dateString)} (${event.monthsFromNow} months)`);
responseLines.push(`- **Version**: ${event.version}`);
responseLines.push(`- **Event**: ${event.phase}`);
responseLines.push('');
});
}
return {
content: [
{
type: 'text',
text: responseLines.join('\n'),
},
],
};
});
// Register tool: Migration planning
server.tool('get-migration-plan', 'Generate a migration plan from one product version to recommended newer versions', {
productName: z.string().describe('The name of the product'),
currentVersion: z.string().describe('The current version to migrate from'),
urgencyLevel: z.enum(['low', 'medium', 'high', 'critical']).optional().describe('Migration urgency level'),
}, async ({ productName, currentVersion, urgencyLevel = 'medium' }) => {
const product = getProductByName(productName);
if (!product) {
return {
content: [
{
type: 'text',
text: `Product "${productName}" not found.`,
},
],
};
}
const sourceVersion = product.versions.find(v => v.name.toLowerCase().includes(currentVersion.toLowerCase()) ||
currentVersion.toLowerCase().includes(v.name.toLowerCase()));
if (!sourceVersion) {
return {
content: [
{
type: 'text',
text: `Version "${currentVersion}" not found for ${productName}.`,
},
],
};
}
const sourceStatus = getLifecycleStatus(sourceVersion);
const now = new Date();
// Find recommended target versions
const recommendedVersions = product.versions
.filter(v => {
const status = getLifecycleStatus(v);
return status === 'Full Support' || status === 'General Availability';
})
.map(v => ({
version: v,
status: getLifecycleStatus(v),
timeRemaining: getTimeRemaining(v)
}))
.sort((a, b) => {
// Prefer Full Support over GA, then by time remaining
if (a.status !== b.status) {
return a.status === 'Full Support' ? -1 : 1;
}
return 0;
});
const responseLines = [
`# Migration Plan: ${product.name}`,
'',
`## Current Version Analysis`,
`- **Version**: ${sourceVersion.name}`,
`- **Current Status**: ${sourceStatus}`,
`- **Time Remaining**: ${getTimeRemaining(sourceVersion)}`,
'',
`## Migration Urgency: ${urgencyLevel.toUpperCase()}`,
''
];
if (sourceStatus === 'End of Life') {
responseLines.push('🚨 **CRITICAL**: Current version is End of Life - immediate migration required!');
}
else if (sourceStatus === 'Maintenance Support') {
responseLines.push('⚠️ **WARNING**: Current version is in Maintenance Support - migration recommended');
}
else {
responseLines.push('✅ **STATUS**: Current version has active support');
}
responseLines.push('', '## Recommended Target Versions', '');
if (recommendedVersions.length === 0) {
responseLines.push('❌ No actively supported versions available for migration.');
}
else {
recommendedVersions.slice(0, 3).forEach((rec, index) => {
responseLines.push(`### Option ${index + 1}: ${rec.version.name}`);
responseLines.push(`- **Status**: ${rec.status}`);
responseLines.push(`- **Support Duration**: ${rec.timeRemaining}`);
responseLines.push(`- **Recommendation**: ${index === 0 ? 'Primary choice' : index === 1 ? 'Alternative' : 'Fallback'}`);
responseLines.push('');
});
}
// Add urgency-based timeline
const urgencyTimelines = {
low: '6-12 months',
medium: '3-6 months',
high: '1-3 months',
critical: 'Immediate (within 30 days)'
};
responseLines.push('## Recommended Timeline');
responseLines.push(`Based on **${urgencyLevel}** urgency: ${urgencyTimelines[urgencyLevel]}`);
return {
content: [
{
type: 'text',
text: responseLines.join('\n'),
},
],
};
});
// Register tool: Compliance and risk assessment
server.tool('get-compliance-report', 'Generate a compliance and risk assessment report for product versions in use', {
productVersions: z.array(z.object({
productName: z.string(),
versionName: z.string()
})).describe('Array of product and version pairs to assess'),
complianceFramework: z.enum(['general', 'pci-dss', 'hipaa', 'sox', 'iso27001']).optional().describe('Compliance framework context'),
}, async ({ productVersions, complianceFramework = 'general' }) => {
const assessments = [];
for (const pv of productVersions) {
const product = getProductByName(pv.productName);
if (!product) {
assessments.push({
productName: pv.productName,
versionName: pv.versionName,
status: 'UNKNOWN',
risk: 'HIGH',
reason: 'Product not found in lifecycle database'
});
continue;
}
const version = product.versions.find(v => v.name.toLowerCase().includes(pv.versionName.toLowerCase()) ||
pv.versionName.toLowerCase().includes(v.name.toLowerCase()));
if (!version) {
assessments.push({
productName: pv.productName,
versionName: pv.versionName,
status: 'UNKNOWN',
risk: 'HIGH',
reason: 'Version not found in lifecycle database'
});
continue;
}
const status = getLifecycleStatus(version);
const timeRemaining = getTimeRemaining(version);
let risk = 'LOW';
let reason = 'Version has active support';
if (status === 'End of Life') {
risk = 'CRITICAL';
reason = 'Version is End of Life - no security updates';
}
else if (status === 'Maintenance Support') {
risk = 'HIGH';
reason = 'Version in maintenance mode - limited updates';
}
else if (status === 'Future Release') {
risk = 'MEDIUM';
reason = 'Version not yet released - may have stability issues';
}
else if (timeRemaining.includes('days remaining') && parseInt(timeRemaining) < 180) {
risk = 'MEDIUM';
reason = 'Version support ending within 6 months';
}
assessments.push({
productName: pv.productName,
versionName: pv.versionName,
status,
risk,
reason,
timeRemaining
});
}
const responseLines = [
`# Compliance Risk Assessment Report`,
`**Framework**: ${complianceFramework.toUpperCase()}`,
`**Generated**: ${new Date().toISOString().split('T')[0]}`,
'',
'## Summary',
''
];
const riskCounts = {
CRITICAL: assessments.filter(a => a.risk === 'CRITICAL').length,
HIGH: assessments.filter(a => a.risk === 'HIGH').length,
MEDIUM: assessments.filter(a => a.risk === 'MEDIUM').length,
LOW: assessments.filter(a => a.risk === 'LOW').length
};
responseLines.push(`- 🔴 **Critical Risk**: ${riskCounts.CRITICAL} products`);
responseLines.push(`- 🟡 **High Risk**: ${riskCounts.HIGH} products`);
responseLines.push(`- 🟠 **Medium Risk**: ${riskCounts.MEDIUM} products`);
responseLines.push(`- 🟢 **Low Risk**: ${riskCounts.LOW} products`);
responseLines.push('');
responseLines.push('## Detailed Assessment', '');
assessments.forEach((assessment) => {
const riskEmoji = {
CRITICAL: '🔴',
HIGH: '🟡',
MEDIUM: '🟠',
LOW: '🟢'
};
responseLines.push(`### ${assessment.productName} ${assessment.versionName} ${riskEmoji[assessment.risk] || '⚪'}`);
responseLines.push(`- **Status**: ${assessment.status}`);
responseLines.push(`- **Risk Level**: ${assessment.risk}`);
responseLines.push(`- **Reason**: ${assessment.reason}`);
if (assessment.timeRemaining) {
responseLines.push(`- **Time Remaining**: ${assessment.timeRemaining}`);
}
responseLines.push('');
});
// Add compliance-specific recommendations
if (complianceFramework !== 'general') {
responseLines.push('## Compliance Framework Considerations', '');
const frameworkGuidance = {
'pci-dss': 'PCI DSS requires supported software versions with security patches. End-of-life versions pose compliance risks.',
'hipaa': 'HIPAA requires administrative safeguards including software updates. Unsupported versions may violate requirements.',
'sox': 'SOX requires IT controls including patch management. Document all version decisions and upgrade plans.',
'iso27001': 'ISO 27001 requires asset management and vulnerability management. Maintain software inventory and update schedules.'
};
responseLines.push(frameworkGuidance[complianceFramework] || '');
}
return {
content: [
{
type: 'text',
text: responseLines.join('\n'),
},
],
};
});
// Register tool: Portfolio optimization analysis
server.tool('analyze-portfolio-optimization', 'Analyze an entire product portfolio and provide optimization recommendations', {
portfolio: z.array(z.object({
productName: z.string(),
versions: z.array(z.string()),
criticality: z.enum(['low', 'medium', 'high', 'critical']).optional()
})).describe('Portfolio of products with their versions and criticality'),
optimizationGoal: z.enum(['cost', 'risk', 'performance', 'compliance']).optional().describe('Primary optimization goal'),
}, async ({ portfolio, optimizationGoal = 'risk' }) => {
const portfolioAnalysis = [];
let totalProducts = 0;
let riskScore = 0;
for (const portfolioItem of portfolio) {
const product = getProductByName(portfolioItem.productName);
if (!product)
continue;
const productAnalysis = {
productName: portfolioItem.productName,
criticality: portfolioItem.criticality || 'medium',
versions: [],
recommendations: [],
riskScore: 0
};
for (const versionName of portfolioItem.versions) {
const version = product.versions.find(v => v.name.toLowerCase().includes(versionName.toLowerCase()));
if (version) {
const status = getLifecycleStatus(version);
const timeRemaining = getTimeRemaining(version);
let versionRisk = 0;
if (status === 'End of Life')
versionRisk = 4;
else if (status === 'Maintenance Support')
versionRisk = 3;
else if (status === 'Full Support' && timeRemaining.includes('days remaining') && parseInt(timeRemaining) < 365)
versionRisk = 2;
else
versionRisk = 1;
productAnalysis.versions.push({
name: versionName,
status,
timeRemaining,
riskScore: versionRisk
});
productAnalysis.riskScore += versionRisk;
}
}
// Generate recommendations based on optimization goal
if (optimizationGoal === 'risk') {
if (productAnalysis.riskScore > 6) {
productAnalysis.recommendations.push('HIGH PRIORITY: Immediate migration required');
}
else if (productAnalysis.riskScore > 3) {
productAnalysis.recommendations.push('MEDIUM PRIORITY: Plan migration within 6 months');
}
}
else if (optimizationGoal === 'cost') {
if (productAnalysis.versions.length > 2) {
productAnalysis.recommendations.push('CONSOLIDATION: Reduce version diversity to lower maintenance costs');
}
}
portfolioAnalysis.push(productAnalysis);
totalProducts++;
riskScore += productAnalysis.riskScore;
}
const averageRisk = totalProducts > 0 ? (riskScore / totalProducts).toFixed(2) : '0';
const responseLines = [
`# Portfolio Optimization Analysis`,
`**Optimization Goal**: ${optimizationGoal.toUpperCase()}`,
`**Total Products**: ${totalProducts}`,
`**Average Risk Score**: ${averageRisk}/4.0`,
'',
'## Executive Summary',
''
];
// Risk assessment
if (parseFloat(averageRisk) >= 3.0) {
responseLines.push('🔴 **HIGH RISK PORTFOLIO** - Immediate action required');
}
else if (parseFloat(averageRisk) >= 2.0) {
responseLines.push('🟡 **MEDIUM RISK PORTFOLIO** - Migration planning recommended');
}
else {
responseLines.push('🟢 **LOW RISK PORTFOLIO** - Good lifecycle management');
}
responseLines.push('', '## Product-by-Product Analysis', '');
portfolioAnalysis.forEach((analysis) => {
responseLines.push(`### ${analysis.productName} (${analysis.criticality.toUpperCase()} criticality)`);
responseLines.push(`**Risk Score**: ${analysis.riskScore}/4.0`);
responseLines.push('');
analysis.versions.forEach((v) => {
responseLines.push(`- **${v.name}**: ${v.status} (${v.timeRemaining})`);
});
if (analysis.recommendations.length > 0) {
responseLines.push('');
responseLines.push('**Recommendations**:');
analysis.recommendations.forEach((rec) => {
responseLines.push(`- ${rec}`);
});
}
responseLines.push('');
});
return {
content: [
{
type: 'text',
text: responseLines.join('\n'),
},
],
};
});
// Register tool: Cost impact analysis
server.tool('calculate-lifecycle-costs', 'Calculate the cost impact of different lifecycle decisions', {
scenarios: z.array(z.object({
name: z.string(),
productName: z.string(),
currentVersion: z.string(),
targetVersion: z.string().optional(),
migrationTimeMonths: z.number().optional(),
systemCount: z.number().optional()
})).describe('Different scenarios to analyze'),
costFactors: z.object({
supportCostPerYear: z.number().optional(),
migrationCostPerSystem: z.number().optional(),
downtimeCostPerHour: z.number().optional(),
securityIncidentCost: z.number().optional()
}).optional().describe('Cost factors for analysis')
}, async ({ scenarios, costFactors = {} }) => {
const { supportCostPerYear = 10000, migrationCostPerSystem = 5000, downtimeCostPerHour = 1000, securityIncidentCost = 100000 } = costFactors;
const responseLines = [
`# Lifecycle Cost Impact Analysis`,
'',
'## Cost Assumptions',
`- Support cost per year: $${supportCostPerYear.toLocaleString()}`,
`- Migration cost per system: $${migrationCostPerSystem.toLocaleString()}`,
`- Downtime cost per hour: $${downtimeCostPerHour.toLocaleString()}`,
`- Security incident cost: $${securityIncidentCost.toLocaleString()}`,
'',
'## Scenario Analysis',
''
];
scenarios.forEach((scenario) => {
const product = getProductByName(scenario.productName);
if (!product)
return;
const currentVersion = product.versions.find(v => v.name.toLowerCase().includes(scenario.currentVersion.toLowerCase()));
if (!currentVersion)
return;
const currentStatus = getLifecycleStatus(currentVersion);
const systemCount = scenario.systemCount || 1;
const migrationTime = scenario.migrationTimeMonths || 3;
let riskMultiplier = 1;
if (currentStatus === 'End of Life')
riskMultiplier = 5;
else if (currentStatus === 'Maintenance Support')
riskMultiplier = 2;
const annualSupportCost = supportCostPerYear * systemCount;
const migrationCost = migrationCostPerSystem * systemCount;
const estimatedDowntimeHours = migrationTime * 4; // 4 hours per month during migration
const downtimeCost = estimatedDowntimeHours * downtimeCostPerHour;
const securityRiskCost = securityIncidentCost * (riskMultiplier - 1) * 0.1; // 10% chance per risk level
const totalCost = annualSupportCost + migrationCost + downtimeCost + securityRiskCost;
responseLines.push(`### ${scenario.name}`);
responseLines.push(`**Product**: ${scenario.productName} ${scenario.currentVersion}`);
responseLines.push(`**Current Status**: ${currentStatus}`);
responseLines.push(`**Systems**: ${systemCount}`);
responseLines.push('');
responseLines.push('**Cost Breakdown**:');
responseLines.push(`- Annual Support: $${annualSupportCost.toLocaleString()}`);
responseLines.push(`- Migration: $${migrationCost.toLocaleString()}`);
responseLines.push(`- Downtime: $${downtimeCost.toLocaleString()}`);
responseLines.push(`- Security Risk: $${securityRiskCost.toLocaleString()}`);
responseLines.push(`- **Total Year 1**: $${totalCost.toLocaleString()}`);
responseLines.push('');
});
return {
content: [
{
type: 'text',
text: responseLines.join('\n'),
},
],
};
});
async function main() {
// Replace with your complete product data
// productData = loadFullProductData();
const transport = new StdioServerTransport();
await server.connect(transport);
console.error('Product Lifecycle MCP Server running on stdio');
}
main().catch((error) => {
console.error('Fatal error in main():', error);
process.exit(1);
});