defect-inspection-tools-mcp-server
Version:
Defect inspection tools server handling defect detection, analysis, and reporting with AI/ML capabilities for quality control
407 lines • 18.2 kB
JavaScript
import { logger } from './logger.js';
import { SanitizationMiddleware } from '../middleware/sanitization-middleware.js';
export class MarkdownProcessor {
// Parse markdown content into structured document
static parseMarkdown(content, options = {}) {
try {
const opts = { ...MarkdownProcessor.DEFAULT_OPTIONS, ...options };
logger.debug('Parsing markdown content', {
contentLength: content.length,
options: opts
});
// Sanitize content if requested
let processedContent = content;
if (opts.sanitize) {
processedContent = SanitizationMiddleware.sanitizeString(content, opts.maxLength, opts.allowHtml);
}
// Limit content length
if (processedContent.length > opts.maxLength) {
processedContent = processedContent.substring(0, opts.maxLength);
}
const document = {
title: this.extractTitle(processedContent),
sections: this.extractSections(processedContent, opts),
tables: this.extractTables(processedContent),
links: this.extractLinks(processedContent),
images: this.extractImages(processedContent),
codeBlocks: this.extractCodeBlocks(processedContent)
};
logger.debug('Markdown parsing completed', {
title: document.title,
sectionsCount: document.sections.length,
tablesCount: document.tables.length,
linksCount: document.links.length,
imagesCount: document.images.length,
codeBlocksCount: document.codeBlocks.length
});
return document;
}
catch (error) {
logger.error('Markdown parsing failed', {
error: error.message,
contentLength: content.length
});
throw error;
}
}
// Convert structured document to markdown
static generateMarkdown(document) {
try {
let markdown = '';
// Add title
if (document.title) {
markdown += `# ${document.title}\n\n`;
}
// Add sections
for (const section of document.sections) {
markdown += this.generateSectionMarkdown(section);
}
// Add tables
for (const table of document.tables) {
markdown += this.generateTableMarkdown(table);
}
// Add code blocks
for (const codeBlock of document.codeBlocks) {
markdown += this.generateCodeBlockMarkdown(codeBlock);
}
logger.debug('Markdown generation completed', {
outputLength: markdown.length
});
return markdown;
}
catch (error) {
logger.error('Markdown generation failed', {
error: error.message
});
throw error;
}
}
// Generate maritime inspection report in markdown format
static generateInspectionReport(vesselData, inspectionData, defects = []) {
try {
const sanitizedVesselData = SanitizationMiddleware.sanitizeToolArguments(vesselData);
const sanitizedInspectionData = SanitizationMiddleware.sanitizeToolArguments(inspectionData);
const sanitizedDefects = defects.map(d => SanitizationMiddleware.sanitizeToolArguments(d));
let report = '';
// Title
report += `# Maritime Inspection Report\n\n`;
// Vessel Information
report += `## Vessel Information\n\n`;
report += `| Property | Value |\n`;
report += `|----------|-------|\n`;
report += `| Vessel Name | ${sanitizedVesselData.vessel_name || 'N/A'} |\n`;
report += `| IMO Number | ${sanitizedVesselData.imo_number || 'N/A'} |\n`;
report += `| Vessel Type | ${sanitizedVesselData.vessel_type || 'N/A'} |\n`;
report += `| Flag State | ${sanitizedVesselData.flag_state || 'N/A'} |\n`;
report += `| Classification Society | ${sanitizedVesselData.class_society || 'N/A'} |\n`;
report += `| Built Year | ${sanitizedVesselData.built_year || 'N/A'} |\n\n`;
// Inspection Details
report += `## Inspection Details\n\n`;
report += `| Property | Value |\n`;
report += `|----------|-------|\n`;
report += `| Inspection Date | ${sanitizedInspectionData.inspection_date || 'N/A'} |\n`;
report += `| Inspector | ${sanitizedInspectionData.inspector || 'N/A'} |\n`;
report += `| Port | ${sanitizedInspectionData.port || 'N/A'} |\n`;
report += `| Inspection Type | ${sanitizedInspectionData.inspection_type || 'N/A'} |\n`;
report += `| Status | ${sanitizedInspectionData.status || 'N/A'} |\n\n`;
// Executive Summary
report += `## Executive Summary\n\n`;
report += `This inspection report covers the ${sanitizedInspectionData.inspection_type || 'routine'} inspection of the vessel ${sanitizedVesselData.vessel_name || 'Unknown'} conducted on ${sanitizedInspectionData.inspection_date || 'N/A'}.\n\n`;
// Defects Summary
if (sanitizedDefects.length > 0) {
report += `## Defects Summary\n\n`;
report += `Total defects found: **${sanitizedDefects.length}**\n\n`;
// Defects by severity
const severityCount = this.countDefectsBySeverity(sanitizedDefects);
report += `### Defects by Severity\n\n`;
report += `| Severity | Count |\n`;
report += `|----------|-------|\n`;
Object.entries(severityCount).forEach(([severity, count]) => {
report += `| ${severity} | ${count} |\n`;
});
report += `\n`;
// Detailed defects
report += `## Detailed Defects\n\n`;
sanitizedDefects.forEach((defect, index) => {
report += `### Defect ${index + 1}: ${defect.defect_type || 'Unknown'}\n\n`;
report += `| Property | Value |\n`;
report += `|----------|-------|\n`;
report += `| Location | ${defect.location || 'N/A'} |\n`;
report += `| Severity | ${defect.severity || 'N/A'} |\n`;
report += `| Status | ${defect.status || 'N/A'} |\n`;
report += `| Description | ${defect.description || 'N/A'} |\n`;
report += `| Corrective Action | ${defect.corrective_action || 'N/A'} |\n`;
report += `| Due Date | ${defect.due_date || 'N/A'} |\n\n`;
});
}
else {
report += `## Defects Summary\n\n`;
report += `No defects were found during this inspection.\n\n`;
}
// Recommendations
report += `## Recommendations\n\n`;
if (sanitizedDefects.length > 0) {
report += `Based on the inspection findings, the following recommendations are made:\n\n`;
report += `1. Address all critical and high-severity defects immediately\n`;
report += `2. Implement corrective actions as specified for each defect\n`;
report += `3. Establish a monitoring system for recurring issues\n`;
report += `4. Conduct follow-up inspections to verify corrections\n`;
report += `5. Review and update maintenance procedures as necessary\n\n`;
}
else {
report += `The vessel appears to be in good condition. Continue with regular maintenance schedules and monitoring.\n\n`;
}
// Compliance Status
report += `## Compliance Status\n\n`;
const complianceStatus = this.determineComplianceStatus(sanitizedDefects);
report += `Overall compliance status: **${complianceStatus}**\n\n`;
// Footer
report += `## Report Information\n\n`;
report += `| Property | Value |\n`;
report += `|----------|-------|\n`;
report += `| Report Generated | ${new Date().toISOString()} |\n`;
report += `| Generated By | Defect Inspection Tools MCP Server |\n`;
report += `| Report Version | 1.0 |\n\n`;
logger.info('Maritime inspection report generated', {
vesselName: sanitizedVesselData.vessel_name,
defectCount: sanitizedDefects.length,
reportLength: report.length
});
return report;
}
catch (error) {
logger.error('Maritime inspection report generation failed', {
error: error.message
});
throw error;
}
}
// Generate compliance summary in markdown format
static generateComplianceSummary(complianceData) {
try {
const sanitizedData = complianceData.map(d => SanitizationMiddleware.sanitizeToolArguments(d));
let summary = '';
// Title
summary += `# Maritime Compliance Summary\n\n`;
// Overview
summary += `## Overview\n\n`;
summary += `This summary covers compliance status for ${sanitizedData.length} vessel(s) or inspection(s).\n\n`;
// Compliance Statistics
const stats = this.calculateComplianceStatistics(sanitizedData);
summary += `## Compliance Statistics\n\n`;
summary += `| Metric | Value |\n`;
summary += `|--------|-------|\n`;
summary += `| Total Vessels/Inspections | ${stats.total} |\n`;
summary += `| Compliant | ${stats.compliant} |\n`;
summary += `| Non-Compliant | ${stats.nonCompliant} |\n`;
summary += `| Compliance Rate | ${stats.complianceRate.toFixed(1)}% |\n\n`;
// Detailed Compliance Data
summary += `## Detailed Compliance Data\n\n`;
summary += `| Vessel/Inspection | Status | Defects | Last Inspection |\n`;
summary += `|------------------|--------|---------|----------------|\n`;
sanitizedData.forEach(item => {
const status = item.compliance_status || 'Unknown';
const defects = item.defect_count || 0;
const lastInspection = item.last_inspection_date || 'N/A';
const name = item.vessel_name || item.inspection_id || 'Unknown';
summary += `| ${name} | ${status} | ${defects} | ${lastInspection} |\n`;
});
summary += `\n`;
// Recommendations
summary += `## Recommendations\n\n`;
if (stats.nonCompliant > 0) {
summary += `### Priority Actions\n\n`;
summary += `1. **Immediate attention required** for ${stats.nonCompliant} non-compliant vessel(s)\n`;
summary += `2. **Conduct detailed inspections** to identify root causes\n`;
summary += `3. **Implement corrective action plans** with clear timelines\n`;
summary += `4. **Establish monitoring systems** for ongoing compliance\n\n`;
}
summary += `### General Recommendations\n\n`;
summary += `1. **Maintain regular inspection schedules** for all vessels\n`;
summary += `2. **Update compliance procedures** based on latest regulations\n`;
summary += `3. **Provide training** on compliance requirements\n`;
summary += `4. **Monitor industry best practices** and regulatory changes\n\n`;
// Footer
summary += `## Summary Information\n\n`;
summary += `| Property | Value |\n`;
summary += `|----------|-------|\n`;
summary += `| Summary Generated | ${new Date().toISOString()} |\n`;
summary += `| Generated By | Defect Inspection Tools MCP Server |\n`;
summary += `| Data Points | ${sanitizedData.length} |\n\n`;
logger.info('Compliance summary generated', {
dataPoints: sanitizedData.length,
complianceRate: stats.complianceRate,
summaryLength: summary.length
});
return summary;
}
catch (error) {
logger.error('Compliance summary generation failed', {
error: error.message
});
throw error;
}
}
// Private helper methods
static extractTitle(content) {
const titleMatch = content.match(/^#\s+(.+)$/m);
return titleMatch ? titleMatch[1].trim() : '';
}
static extractSections(content, options) {
const sections = [];
const headingRegex = /^(#{1,6})\s+(.+)$/gm;
let match;
while ((match = headingRegex.exec(content)) !== null) {
const level = match[1].length;
if (options.headingLevels?.includes(level)) {
sections.push({
level,
title: match[2].trim(),
content: '',
subsections: []
});
}
}
return sections;
}
static extractTables(content) {
const tables = [];
const tableRegex = /\|(.+)\|\s*\n\|[-\s|:]+\|\s*\n((?:\|.+\|\s*\n?)*)/gm;
let match;
while ((match = tableRegex.exec(content)) !== null) {
const headers = match[1].split('|').map(h => h.trim()).filter(h => h);
const rowsText = match[2];
const rows = rowsText.split('\n')
.filter(row => row.trim())
.map(row => row.split('|').map(cell => cell.trim()).filter(cell => cell));
if (headers.length > 0 && rows.length > 0) {
tables.push({ headers, rows });
}
}
return tables;
}
static extractLinks(content) {
const links = [];
const linkRegex = /\[([^\]]+)\]\(([^)]+)(?:\s+"([^"]+)")?\)/g;
let match;
while ((match = linkRegex.exec(content)) !== null) {
links.push({
text: match[1],
url: match[2],
title: match[3]
});
}
return links;
}
static extractImages(content) {
const images = [];
const imageRegex = /!\[([^\]]*)\]\(([^)]+)(?:\s+"([^"]+)")?\)/g;
let match;
while ((match = imageRegex.exec(content)) !== null) {
images.push({
alt: match[1],
url: match[2],
title: match[3]
});
}
return images;
}
static extractCodeBlocks(content) {
const codeBlocks = [];
const codeBlockRegex = /```(\w+)?\n([\s\S]*?)```/g;
let match;
while ((match = codeBlockRegex.exec(content)) !== null) {
codeBlocks.push({
language: match[1],
code: match[2]
});
}
return codeBlocks;
}
static generateSectionMarkdown(section) {
let markdown = `${'#'.repeat(section.level)} ${section.title}\n\n`;
if (section.content) {
markdown += `${section.content}\n\n`;
}
if (section.subsections) {
for (const subsection of section.subsections) {
markdown += this.generateSectionMarkdown(subsection);
}
}
return markdown;
}
static generateTableMarkdown(table) {
let markdown = '';
if (table.caption) {
markdown += `**${table.caption}**\n\n`;
}
// Headers
markdown += `| ${table.headers.join(' | ')} |\n`;
markdown += `| ${table.headers.map(() => '---').join(' | ')} |\n`;
// Rows
for (const row of table.rows) {
markdown += `| ${row.join(' | ')} |\n`;
}
markdown += '\n';
return markdown;
}
static generateCodeBlockMarkdown(codeBlock) {
let markdown = '```';
if (codeBlock.language) {
markdown += codeBlock.language;
}
markdown += `\n${codeBlock.code}\n\`\`\`\n\n`;
return markdown;
}
static countDefectsBySeverity(defects) {
const severityCount = {
'Critical': 0,
'High': 0,
'Medium': 0,
'Low': 0,
'Unknown': 0
};
defects.forEach(defect => {
const severity = defect.severity || 'Unknown';
severityCount[severity] = (severityCount[severity] || 0) + 1;
});
return severityCount;
}
static determineComplianceStatus(defects) {
const criticalDefects = defects.filter(d => d.severity === 'Critical').length;
const highDefects = defects.filter(d => d.severity === 'High').length;
if (criticalDefects > 0) {
return 'Non-Compliant (Critical Issues)';
}
else if (highDefects > 0) {
return 'Non-Compliant (High Priority Issues)';
}
else if (defects.length > 0) {
return 'Compliant with Minor Issues';
}
else {
return 'Fully Compliant';
}
}
static calculateComplianceStatistics(data) {
const total = data.length;
const compliant = data.filter(item => item.compliance_status === 'Compliant' ||
item.compliance_status === 'Fully Compliant').length;
const nonCompliant = total - compliant;
const complianceRate = total > 0 ? (compliant / total) * 100 : 0;
return {
total,
compliant,
nonCompliant,
complianceRate
};
}
}
MarkdownProcessor.DEFAULT_OPTIONS = {
sanitize: true,
maxLength: 100000,
allowHtml: false,
preserveLineBreaks: true,
headingLevels: [1, 2, 3, 4, 5, 6]
};
//# sourceMappingURL=markdown.js.map