#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
ListResourcesRequestSchema,
ReadResourceRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
// Import mock data
import {
mockProductionOrders,
mockWorkOrders,
mockEquipment,
type ProductionOrder,
type WorkOrder,
type Equipment,
} from "./mock-data/mes-data.js";
import {
mockMaintenanceTasks,
mockAssets,
mockMaintenanceHistory,
type MaintenanceTask,
type Asset,
type MaintenanceHistory,
} from "./mock-data/cmms-data.js";
import {
mockSensors,
mockSensorReadings,
mockDevices,
mockAlerts,
type Sensor,
type SensorReading,
type Device,
type Alert,
} from "./mock-data/iot-data.js";
class CMMSMCPServer {
private server: Server;
constructor() {
this.server = new Server(
{
name: "cmms-mcp-server",
version: "1.0.0",
},
{
capabilities: {
tools: {},
resources: {},
},
}
);
this.setupHandlers();
}
private setupHandlers() {
// List available tools
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
// MES Tools
{
name: "get_production_orders",
description:
"Get production orders from MES system. Can filter by status.",
inputSchema: {
type: "object",
properties: {
status: {
type: "string",
enum: ["planned", "in-progress", "completed", "cancelled"],
description: "Filter by production order status",
},
orderId: {
type: "string",
description: "Get specific production order by ID",
},
},
},
},
{
name: "get_work_orders",
description:
"Get work orders from MES system. Can filter by status or production order.",
inputSchema: {
type: "object",
properties: {
status: {
type: "string",
enum: ["pending", "in-progress", "completed", "on-hold"],
description: "Filter by work order status",
},
productionOrderId: {
type: "string",
description: "Filter by production order ID",
},
},
},
},
{
name: "get_equipment",
description:
"Get equipment status from MES system. Can filter by status or get specific equipment.",
inputSchema: {
type: "object",
properties: {
status: {
type: "string",
enum: ["running", "idle", "maintenance", "error"],
description: "Filter by equipment status",
},
equipmentId: {
type: "string",
description: "Get specific equipment by ID",
},
},
},
},
// CMMS Tools
{
name: "get_maintenance_tasks",
description:
"Get maintenance tasks from CMMS system. Can filter by status, priority, or type.",
inputSchema: {
type: "object",
properties: {
status: {
type: "string",
enum: [
"scheduled",
"in-progress",
"completed",
"cancelled",
"overdue",
],
description: "Filter by task status",
},
priority: {
type: "string",
enum: ["low", "medium", "high", "critical"],
description: "Filter by priority",
},
taskType: {
type: "string",
enum: ["preventive", "corrective", "inspection", "calibration"],
description: "Filter by task type",
},
assetId: {
type: "string",
description: "Filter by asset ID",
},
},
},
},
{
name: "get_assets",
description:
"Get assets from CMMS system. Can filter by status or get specific asset.",
inputSchema: {
type: "object",
properties: {
status: {
type: "string",
enum: [
"operational",
"maintenance",
"out-of-service",
"retired",
],
description: "Filter by asset status",
},
assetId: {
type: "string",
description: "Get specific asset by ID",
},
},
},
},
{
name: "get_maintenance_history",
description:
"Get maintenance history from CMMS system. Can filter by asset or date range.",
inputSchema: {
type: "object",
properties: {
assetId: {
type: "string",
description: "Filter by asset ID",
},
startDate: {
type: "string",
description: "Start date for history (ISO format)",
},
endDate: {
type: "string",
description: "End date for history (ISO format)",
},
},
},
},
{
name: "create_maintenance_task",
description: "Create a new maintenance task in CMMS system.",
inputSchema: {
type: "object",
properties: {
assetId: {
type: "string",
description: "Asset ID for the maintenance task",
},
taskType: {
type: "string",
enum: ["preventive", "corrective", "inspection", "calibration"],
description: "Type of maintenance task",
},
priority: {
type: "string",
enum: ["low", "medium", "high", "critical"],
description: "Priority of the task",
},
scheduledDate: {
type: "string",
description: "Scheduled date (ISO format)",
},
dueDate: {
type: "string",
description: "Due date (ISO format)",
},
assignedTo: {
type: "string",
description: "Technician ID assigned to the task",
},
description: {
type: "string",
description: "Description of the maintenance task",
},
estimatedDuration: {
type: "number",
description: "Estimated duration in minutes",
},
},
required: [
"assetId",
"taskType",
"priority",
"scheduledDate",
"dueDate",
"assignedTo",
"description",
],
},
},
// IoT Tools
{
name: "get_sensors",
description:
"Get sensors from IoT system. Can filter by type, status, or equipment.",
inputSchema: {
type: "object",
properties: {
type: {
type: "string",
enum: [
"temperature",
"pressure",
"vibration",
"humidity",
"flow",
"level",
],
description: "Filter by sensor type",
},
status: {
type: "string",
enum: ["active", "inactive", "error"],
description: "Filter by sensor status",
},
equipmentId: {
type: "string",
description: "Filter by equipment ID",
},
},
},
},
{
name: "get_sensor_readings",
description:
"Get sensor readings from IoT system. Can filter by sensor, status, or time range.",
inputSchema: {
type: "object",
properties: {
sensorId: {
type: "string",
description: "Filter by sensor ID",
},
status: {
type: "string",
enum: ["normal", "warning", "critical"],
description: "Filter by reading status",
},
hours: {
type: "number",
description: "Get readings from last N hours",
},
},
},
},
{
name: "get_devices",
description: "Get IoT devices. Can filter by status or type.",
inputSchema: {
type: "object",
properties: {
status: {
type: "string",
enum: ["online", "offline", "error"],
description: "Filter by device status",
},
type: {
type: "string",
description: "Filter by device type",
},
},
},
},
{
name: "get_alerts",
description:
"Get IoT alerts. Can filter by severity, acknowledged status, or device.",
inputSchema: {
type: "object",
properties: {
severity: {
type: "string",
enum: ["info", "warning", "critical"],
description: "Filter by alert severity",
},
acknowledged: {
type: "boolean",
description: "Filter by acknowledged status",
},
deviceId: {
type: "string",
description: "Filter by device ID",
},
},
},
},
{
name: "acknowledge_alert",
description: "Acknowledge an IoT alert.",
inputSchema: {
type: "object",
properties: {
alertId: {
type: "string",
description: "Alert ID to acknowledge",
},
acknowledgedBy: {
type: "string",
description: "User ID acknowledging the alert",
},
},
required: ["alertId", "acknowledgedBy"],
},
},
],
}));
// Handle tool calls
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
// MES Tools
case "get_production_orders":
return this.handleGetProductionOrders(args as any);
case "get_work_orders":
return this.handleGetWorkOrders(args as any);
case "get_equipment":
return this.handleGetEquipment(args as any);
// CMMS Tools
case "get_maintenance_tasks":
return this.handleGetMaintenanceTasks(args as any);
case "get_assets":
return this.handleGetAssets(args as any);
case "get_maintenance_history":
return this.handleGetMaintenanceHistory(args as any);
case "create_maintenance_task":
return this.handleCreateMaintenanceTask(args as any);
// IoT Tools
case "get_sensors":
return this.handleGetSensors(args as any);
case "get_sensor_readings":
return this.handleGetSensorReadings(args as any);
case "get_devices":
return this.handleGetDevices(args as any);
case "get_alerts":
return this.handleGetAlerts(args as any);
case "acknowledge_alert":
return this.handleAcknowledgeAlert(args as any);
default:
throw new Error(`Unknown tool: ${name}`);
}
} catch (error) {
return {
content: [
{
type: "text",
text: `Error: ${
error instanceof Error ? error.message : String(error)
}`,
},
],
isError: true,
};
}
});
// List available resources
this.server.setRequestHandler(ListResourcesRequestSchema, async () => ({
resources: [
{
uri: "mes://production-orders",
name: "MES Production Orders",
description: "All production orders from MES system",
mimeType: "application/json",
},
{
uri: "mes://equipment",
name: "MES Equipment",
description: "All equipment from MES system",
mimeType: "application/json",
},
{
uri: "cmms://maintenance-tasks",
name: "CMMS Maintenance Tasks",
description: "All maintenance tasks from CMMS system",
mimeType: "application/json",
},
{
uri: "cmms://assets",
name: "CMMS Assets",
description: "All assets from CMMS system",
mimeType: "application/json",
},
{
uri: "iot://sensors",
name: "IoT Sensors",
description: "All sensors from IoT system",
mimeType: "application/json",
},
{
uri: "iot://alerts",
name: "IoT Alerts",
description: "All active alerts from IoT system",
mimeType: "application/json",
},
],
}));
// Handle resource reads
this.server.setRequestHandler(
ReadResourceRequestSchema,
async (request) => {
const { uri } = request.params;
try {
switch (uri) {
case "mes://production-orders":
return {
contents: [
{
uri,
mimeType: "application/json",
text: JSON.stringify(mockProductionOrders, null, 2),
},
],
};
case "mes://equipment":
return {
contents: [
{
uri,
mimeType: "application/json",
text: JSON.stringify(mockEquipment, null, 2),
},
],
};
case "cmms://maintenance-tasks":
return {
contents: [
{
uri,
mimeType: "application/json",
text: JSON.stringify(mockMaintenanceTasks, null, 2),
},
],
};
case "cmms://assets":
return {
contents: [
{
uri,
mimeType: "application/json",
text: JSON.stringify(mockAssets, null, 2),
},
],
};
case "iot://sensors":
return {
contents: [
{
uri,
mimeType: "application/json",
text: JSON.stringify(mockSensors, null, 2),
},
],
};
case "iot://alerts":
return {
contents: [
{
uri,
mimeType: "application/json",
text: JSON.stringify(
mockAlerts.filter((a) => !a.acknowledged),
null,
2
),
},
],
};
default:
throw new Error(`Unknown resource: ${uri}`);
}
} catch (error) {
return {
contents: [
{
uri,
mimeType: "text/plain",
text: `Error: ${
error instanceof Error ? error.message : String(error)
}`,
},
],
};
}
}
);
}
// MES Handlers
private handleGetProductionOrders(args: {
status?: string;
orderId?: string;
}) {
let orders = [...mockProductionOrders];
if (args.orderId) {
orders = orders.filter((o) => o.id === args.orderId);
} else if (args.status) {
orders = orders.filter((o) => o.status === args.status);
}
return {
content: [
{
type: "text",
text: JSON.stringify(orders, null, 2),
},
],
};
}
private handleGetWorkOrders(args: {
status?: string;
productionOrderId?: string;
}) {
let orders = [...mockWorkOrders];
if (args.productionOrderId) {
orders = orders.filter(
(o) => o.productionOrderId === args.productionOrderId
);
}
if (args.status) {
orders = orders.filter((o) => o.status === args.status);
}
return {
content: [
{
type: "text",
text: JSON.stringify(orders, null, 2),
},
],
};
}
private handleGetEquipment(args: { status?: string; equipmentId?: string }) {
let equipment = [...mockEquipment];
if (args.equipmentId) {
equipment = equipment.filter((e) => e.id === args.equipmentId);
} else if (args.status) {
equipment = equipment.filter((e) => e.status === args.status);
}
return {
content: [
{
type: "text",
text: JSON.stringify(equipment, null, 2),
},
],
};
}
// CMMS Handlers
private handleGetMaintenanceTasks(args: {
status?: string;
priority?: string;
taskType?: string;
assetId?: string;
}) {
let tasks = [...mockMaintenanceTasks];
if (args.assetId) {
tasks = tasks.filter((t) => t.assetId === args.assetId);
}
if (args.status) {
tasks = tasks.filter((t) => t.status === args.status);
}
if (args.priority) {
tasks = tasks.filter((t) => t.priority === args.priority);
}
if (args.taskType) {
tasks = tasks.filter((t) => t.taskType === args.taskType);
}
return {
content: [
{
type: "text",
text: JSON.stringify(tasks, null, 2),
},
],
};
}
private handleGetAssets(args: { status?: string; assetId?: string }) {
let assets = [...mockAssets];
if (args.assetId) {
assets = assets.filter((a) => a.id === args.assetId);
} else if (args.status) {
assets = assets.filter((a) => a.status === args.status);
}
return {
content: [
{
type: "text",
text: JSON.stringify(assets, null, 2),
},
],
};
}
private handleGetMaintenanceHistory(args: {
assetId?: string;
startDate?: string;
endDate?: string;
}) {
let history = [...mockMaintenanceHistory];
if (args.assetId) {
history = history.filter((h) => h.assetId === args.assetId);
}
if (args.startDate) {
const start = new Date(args.startDate);
history = history.filter((h) => new Date(h.completedDate) >= start);
}
if (args.endDate) {
const end = new Date(args.endDate);
history = history.filter((h) => new Date(h.completedDate) <= end);
}
return {
content: [
{
type: "text",
text: JSON.stringify(history, null, 2),
},
],
};
}
private handleCreateMaintenanceTask(args: {
assetId: string;
taskType: string;
priority: string;
scheduledDate: string;
dueDate: string;
assignedTo: string;
description: string;
estimatedDuration?: number;
}) {
const asset = mockAssets.find((a) => a.id === args.assetId);
if (!asset) {
throw new Error(`Asset not found: ${args.assetId}`);
}
const newTask: MaintenanceTask = {
id: `mt-${String(mockMaintenanceTasks.length + 1).padStart(3, "0")}`,
taskNumber: `MT-2024-${String(mockMaintenanceTasks.length + 1).padStart(
3,
"0"
)}`,
assetId: args.assetId,
assetName: asset.name,
taskType: args.taskType as any,
priority: args.priority as any,
status: "scheduled",
scheduledDate: args.scheduledDate,
dueDate: args.dueDate,
assignedTo: args.assignedTo,
description: args.description,
estimatedDuration: args.estimatedDuration || 240,
};
mockMaintenanceTasks.push(newTask);
return {
content: [
{
type: "text",
text: JSON.stringify(newTask, null, 2),
},
],
};
}
// IoT Handlers
private handleGetSensors(args: {
type?: string;
status?: string;
equipmentId?: string;
}) {
let sensors = [...mockSensors];
if (args.equipmentId) {
sensors = sensors.filter((s) => s.equipmentId === args.equipmentId);
}
if (args.type) {
sensors = sensors.filter((s) => s.type === args.type);
}
if (args.status) {
sensors = sensors.filter((s) => s.status === args.status);
}
return {
content: [
{
type: "text",
text: JSON.stringify(sensors, null, 2),
},
],
};
}
private handleGetSensorReadings(args: {
sensorId?: string;
status?: string;
hours?: number;
}) {
let readings = [...mockSensorReadings];
if (args.sensorId) {
readings = readings.filter((r) => r.sensorId === args.sensorId);
}
if (args.status) {
readings = readings.filter((r) => r.status === args.status);
}
if (args.hours) {
const cutoff = new Date(Date.now() - args.hours * 3600000);
readings = readings.filter((r) => new Date(r.timestamp) >= cutoff);
}
// Sort by timestamp descending
readings.sort(
(a, b) =>
new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()
);
return {
content: [
{
type: "text",
text: JSON.stringify(readings, null, 2),
},
],
};
}
private handleGetDevices(args: { status?: string; type?: string }) {
let devices = [...mockDevices];
if (args.status) {
devices = devices.filter((d) => d.status === args.status);
}
if (args.type) {
devices = devices.filter((d) => d.type === args.type);
}
return {
content: [
{
type: "text",
text: JSON.stringify(devices, null, 2),
},
],
};
}
private handleGetAlerts(args: {
severity?: string;
acknowledged?: boolean;
deviceId?: string;
}) {
let alerts = [...mockAlerts];
if (args.deviceId) {
alerts = alerts.filter((a) => a.deviceId === args.deviceId);
}
if (args.severity) {
alerts = alerts.filter((a) => a.severity === args.severity);
}
if (args.acknowledged !== undefined) {
alerts = alerts.filter((a) => a.acknowledged === args.acknowledged);
}
// Sort by timestamp descending
alerts.sort(
(a, b) =>
new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()
);
return {
content: [
{
type: "text",
text: JSON.stringify(alerts, null, 2),
},
],
};
}
private handleAcknowledgeAlert(args: {
alertId: string;
acknowledgedBy: string;
}) {
const alert = mockAlerts.find((a) => a.id === args.alertId);
if (!alert) {
throw new Error(`Alert not found: ${args.alertId}`);
}
alert.acknowledged = true;
alert.acknowledgedBy = args.acknowledgedBy;
alert.acknowledgedAt = new Date().toISOString();
return {
content: [
{
type: "text",
text: JSON.stringify(alert, null, 2),
},
],
};
}
async run() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error("CMMS MCP Server running on stdio");
}
}
// Start the server
const server = new CMMSMCPServer();
server.run().catch(console.error);