AutomationFlowsGeneral › Openshift Performance Metrics - Mcp

Openshift Performance Metrics - Mcp

OpenShift Performance Metrics - MCP. Event-driven trigger; 5 nodes.

Event trigger★★★★☆ complexity5 nodes
General Trigger: Event Nodes: 5 Complexity: ★★★★☆ Added:

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "name": "OpenShift Performance Metrics - MCP",
  "nodes": [
    {
      "parameters": {},
      "id": "trigger",
      "name": "Manual Trigger",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        180,
        300
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "ns",
              "name": "namespace",
              "value": "openshift-lightspeed",
              "type": "string"
            },
            {
              "id": "email",
              "name": "destinationEmail",
              "value": "maximiliano.pizarro.5@gmail.com",
              "type": "string"
            },
            {
              "id": "mcpHost",
              "name": "mcpHost",
              "value": "field-content-ols.openshift-lightspeed.svc.cluster.local",
              "type": "string"
            },
            {
              "id": "mcpPort",
              "name": "mcpPort",
              "value": "8080",
              "type": "string"
            },
            {
              "id": "tool",
              "name": "toolName",
              "value": "getPerformanceMetrics",
              "type": "string"
            },
            {
              "id": "litellmHost",
              "name": "litellmHost",
              "value": "field-content-ols-litellm.openshift-lightspeed.svc.cluster.local",
              "type": "string"
            },
            {
              "id": "litellmPort",
              "name": "litellmPort",
              "value": "4000",
              "type": "string"
            },
            {
              "id": "litellmApiKey",
              "name": "litellmApiKey",
              "value": "sk-openshift-mcp-1234",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "set-params",
      "name": "Set Parameters",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        400,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "const http = require('http');\n\nfunction mcpRequest(host, port, body, sessionId) {\n  return new Promise((resolve, reject) => {\n    const data = JSON.stringify(body);\n    const headers = { 'Content-Type': 'application/json', 'Accept': 'application/json, text/event-stream', 'Content-Length': Buffer.byteLength(data) };\n    if (sessionId) headers['Mcp-Session-Id'] = sessionId;\n    const req = http.request({ hostname: host, port, path: '/mcp', method: 'POST', headers }, (res) => {\n      let body = '';\n      res.on('data', (chunk) => body += chunk);\n      res.on('end', () => {\n        const lines = body.split('\\n');\n        let jsonData = '';\n        for (const line of lines) { if (line.startsWith('data: ')) jsonData = line.substring(6); }\n        resolve({ status: res.statusCode, headers: res.headers, body: jsonData || body });\n      });\n    });\n    req.on('error', reject);\n    req.write(data);\n    req.end();\n  });\n}\n\nasync function callMcpTool(host, port, toolName, toolArgs) {\n  const init = await mcpRequest(host, port, { jsonrpc: '2.0', id: 1, method: 'initialize', params: { protocolVersion: '2024-11-05', capabilities: {}, clientInfo: { name: 'n8n-workflow', version: '1.0' } } });\n  const sid = init.headers['mcp-session-id'];\n  await mcpRequest(host, port, { jsonrpc: '2.0', method: 'notifications/initialized' }, sid);\n  const result = await mcpRequest(host, port, { jsonrpc: '2.0', id: 3, method: 'tools/call', params: { name: toolName, arguments: toolArgs } }, sid);\n  const parsed = JSON.parse(result.body);\n  return parsed.result?.content?.[0]?.text || 'Error: ' + JSON.stringify(parsed.error);\n}\n\nconst j = $input.first().json;\nconst host = j.mcpHost;\nconst port = parseInt(j.mcpPort, 10);\nconst mcpOutput = await callMcpTool(host, port, j.toolName, { namespace: j.namespace });\nreturn [{ json: { ...j, mcpOutput } }];\n"
      },
      "id": "mcp-call",
      "name": "MCP Tool Call",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        620,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "const http = require('http');\nconst input = $input.first().json;\nconst litellmHost = input.litellmHost;\nconst litellmPort = parseInt(input.litellmPort, 10);\nconst litellmApiKey = input.litellmApiKey || '';\nconst toolName = input.toolName;\nconst namespace = input.namespace;\nconst mcpOutputFull = input.mcpOutput || '';\nconst mcpOutput = mcpOutputFull.length > 800 ? mcpOutputFull.substring(0, 800) + '\\n[... truncated for AI analysis, see Raw MCP Output below for full data]' : mcpOutputFull;\nconst systemPrompt = 'Analyze this OpenShift MCP output for tool \"' + toolName + '\" in namespace \"' + namespace + '\". Reply with: 1) HTML table of key data, 2) Health status (Healthy/Warning/Critical). Be concise, use inline CSS.';\nconst requestBody = JSON.stringify({\n  model: 'granite',\n  messages: [\n    { role: 'system', content: systemPrompt },\n    { role: 'user', content: mcpOutput }\n  ],\n  temperature: 0.3,\n  max_tokens: 1024\n});\nreturn new Promise((resolve, reject) => {\n  const req = http.request({\n    hostname: litellmHost,\n    port: litellmPort,\n    path: '/v1/chat/completions',\n    method: 'POST',\n    headers: {\n      'Content-Type': 'application/json',\n      'Authorization': 'Bearer ' + litellmApiKey,\n      'Content-Length': Buffer.byteLength(requestBody)\n    }\n  }, (res) => {\n    let data = '';\n    res.on('data', (chunk) => { data += chunk; });\n    res.on('end', () => {\n      try {\n        const parsed = JSON.parse(data);\n        let rawAI = parsed.choices?.[0]?.message?.content || 'AI analysis unavailable';\n        rawAI = rawAI.replace(/<think>[\\s\\S]*?<\\/think>/g, '').trim();\n        const aiAnalysis = rawAI.length > 1800 ? rawAI.substring(0, 1800) + '\n[... truncated ...]' : rawAI;\n        const model = parsed.model || 'deepseek-r1-distill-qwen-14b';\n        resolve([{ json: { ...input, aiAnalysis, aiModel: model } }]);\n      } catch (e) {\n        resolve([{ json: { ...input, aiAnalysis: 'AI analysis failed: ' + e.message, aiModel: 'error' } }]);\n      }\n    });\n  });\n  req.on('error', (e) => {\n    resolve([{ json: { ...input, aiAnalysis: 'AI service unavailable: ' + e.message, aiModel: 'unreachable' } }]);\n  });\n  req.write(requestBody);\n  req.end();\n});\n"
      },
      "id": "ai-format",
      "name": "AI Format & Explain",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        840,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "const http = require('http');\nconst input = $input.first().json;\nconst namespace = input.namespace;\nconst email = input.destinationEmail;\nconst toolName = input.toolName;\nconst mcpOutput = input.mcpOutput || '';\nconst aiAnalysis = input.aiAnalysis || '';\nconst aiModel = input.aiModel || 'granite';\nconst ts = new Date().toISOString();\nconst title = \"Performance Metrics Report\";\nconst subtitle = \"Resource usage and performance monitoring via MCP\";\nconst escapedOutput = mcpOutput.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');\nconst html = `<html><body style=\"margin:0;padding:0;background:#f0f0f0;font-family:'Red Hat Display',Arial,sans-serif;\">\n<table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" style=\"background:#f0f0f0;\"><tr><td align=\"center\" style=\"padding:24px;\">\n<table width=\"640\" style=\"max-width:640px;width:100%;\">\n<tr><td style=\"background:#151515;padding:16px 32px;border-radius:8px 8px 0 0;\">\n<span style=\"color:#EE0000;font-size:20px;font-weight:700;\">Red Hat</span>\n<span style=\"float:right;color:#C6C6C6;font-size:12px;line-height:28px;\">OpenShift Developer Sandbox</span></td></tr>\n<tr><td style=\"background:#DC382D;padding:28px 32px;\">\n<h1 style=\"margin:0;font-size:24px;color:#FFF;\">${title}</h1>\n<p style=\"margin:6px 0 0;font-size:14px;color:rgba(255,255,255,.85);\">${subtitle}</p></td></tr>\n<tr><td style=\"background:#292929;padding:0;\">\n<table width=\"100%\"><tr>\n<td style=\"padding:12px 16px;text-align:center;color:#A3A3A3;font-size:11px;border-right:1px solid #3C3C3C;width:25%;\">\n<b style=\"display:block;color:#FFF;font-size:13px;\">${namespace}</b>Namespace</td>\n<td style=\"padding:12px 16px;text-align:center;color:#A3A3A3;font-size:11px;border-right:1px solid #3C3C3C;width:25%;\">\n<b style=\"display:block;color:#FFF;font-size:13px;\">${ts}</b>Generated</td>\n<td style=\"padding:12px 16px;text-align:center;color:#A3A3A3;font-size:11px;border-right:1px solid #3C3C3C;width:25%;\">\n<b style=\"display:block;color:#FFF;font-size:13px;\">${toolName}</b>MCP Tool</td>\n<td style=\"padding:12px 16px;text-align:center;color:#A3A3A3;font-size:11px;width:25%;\">\n<b style=\"display:block;color:#FFF;font-size:13px;\">${aiModel}</b>AI Model</td>\n</tr></table></td></tr>\n<tr><td style=\"background:#FFF;padding:28px 32px;\">\n<h2 style=\"margin:0 0 16px;font-size:17px;border-bottom:2px solid #DC382D;padding-bottom:10px;\">AI Analysis</h2>\n<div style=\"padding:8px 0;font-size:14px;line-height:1.6;\">${aiAnalysis}</div>\n</td></tr>\n<tr><td style=\"background:#FFF;padding:0 32px 28px 32px;\">\n<h2 style=\"margin:0 0 16px;font-size:17px;border-bottom:2px solid #292929;padding-bottom:10px;color:#6A6E73;\">Raw MCP Output</h2>\n<pre style=\"background:#1E1E1E;color:#D4D4D4;padding:16px;border-radius:6px;overflow-x:auto;font-size:12px;line-height:1.5;white-space:pre-wrap;word-wrap:break-word;\">${escapedOutput}</pre>\n</td></tr>\n<tr><td style=\"background:#F5F5F5;padding:16px 32px;border-top:1px solid #E0E0E0;text-align:center;\">\n<span style=\"display:inline-block;background:#EE0000;color:white;font-size:10px;font-weight:700;padding:4px 10px;border-radius:3px;\">RED HAT</span>\n<span style=\"font-size:11px;color:#6A6E73;margin:0 8px;\">OpenShift MCP Server</span>\n<span style=\"font-size:11px;color:#DC382D;font-weight:600;margin:0 8px;\">n8n</span>\n</td></tr>\n<tr><td style=\"background:#151515;padding:20px 32px;border-radius:0 0 8px 8px;text-align:center;\">\n<p style=\"margin:0;font-size:12px;color:#A3A3A3;\">Auto-generated by n8n on <b style=\"color:#FFF;\">Red Hat OpenShift Developer Sandbox</b></p>\n</td></tr></table></td></tr></table></body></html>`;\nconst subject = `[Red Hat OpenShift] ${title} | ${namespace} | ${ts}`;\nconst mailBody = JSON.stringify({\n  From: { Name: 'n8n Workflow', Email: 'workflow@n8n.local' },\n  To: [{ Name: 'Admin', Email: email }],\n  Subject: subject,\n  HTML: html\n});\nreturn new Promise((resolve, reject) => {\n  const req = http.request({\n    hostname: 'n8n-mailpit',\n    port: 8025,\n    path: '/api/v1/send',\n    method: 'POST',\n    headers: {\n      'Content-Type': 'application/json',\n      'Content-Length': Buffer.byteLength(mailBody)\n    }\n  }, (res) => {\n    let data = '';\n    res.on('data', (chunk) => { data += chunk; });\n    res.on('end', () => {\n      resolve([{ json: { mailpitStatus: res.statusCode, mailpitResponse: data, subject } }]);\n    });\n  });\n  req.on('error', reject);\n  req.write(mailBody);\n  req.end();\n});\n"
      },
      "id": "report-email",
      "name": "Build Report & Send Email",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1060,
        300
      ]
    }
  ],
  "connections": {
    "Manual Trigger": {
      "main": [
        [
          {
            "node": "Set Parameters",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Parameters": {
      "main": [
        [
          {
            "node": "MCP Tool Call",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "MCP Tool Call": {
      "main": [
        [
          {
            "node": "AI Format & Explain",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Format & Explain": {
      "main": [
        [
          {
            "node": "Build Report & Send Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "staticData": null,
  "active": false
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

OpenShift Performance Metrics - MCP. Event-driven trigger; 5 nodes.

Source: https://github.com/maximilianoPizarro/test-drive-pe-oscg/blob/09e735c5d24529c3d70207baaa5cac1b34d55967/examples/helm/components/connectivity-link-openshift-lightspeed/workflows/workflow-resource-quota-monitor.json — original creator credit. Request a take-down →

More General workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

General

Blotato. Uses googleSheets, @blotato/n8n-nodes-blotato. Event-driven trigger; 65 nodes.

Google Sheets, @Blotato/N8N Nodes Blotato
General

This template is a hands-on, practical exam designed to help you master n8n Expressions—the key to accessing and manipulating data in your workflows.

Stop And Error
General

This template is a hands-on, practical exam designed to test your understanding of the fundamental JSON data types. It's the perfect way to solidify your knowledge after learning the basics.

Stop And Error
General

Agendamiento. Uses n8n-nodes-evolution-api, redis, dataTable, executeWorkflowTrigger. Event-driven trigger; 60 nodes.

N8N Nodes Evolution Api, Redis, Data Table +2
General

Kv Cloudflare Key Value Database Full Api Integration Workflow. Uses stickyNote, httpRequest, manualTrigger. Event-driven trigger; 47 nodes.

HTTP Request