mcpField
M
mid-server

mid-server

github.com/serac-labs云与 DevOps7758 次安装9 周前更新
代码仓库

关于 mid-server

面向 ServiceNow MID Server 管理的技能,说明 ECC 队列通信、脚本执行、探针与传感器配置,以及远程主机编排和状态监控。

主要功能

  1. 01通过 ECC 队列发送命令
  2. 02在 MID Server 执行脚本
  3. 03创建探针与传感器
  4. 04远程 PowerShell 与 SSH
  5. 05监控 MID Server 状态

适用场景

  1. 01查看 MID Server 与 ECC 队列状态
  2. 02测试 MID 脚本执行流程
  3. 03配置自定义发现探针和传感器

MCP 相关

文档介绍了使用 snow_query_table 查询 MID 与 ECC 表、snow_artifact_manage 查找探针和传感器,以及 snow_execute_script 测试脚本。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/serac-labs/serac --skill mid-server

安装后在 Claude Code 中输入/mid-server确认已加载。

详细介绍

ServiceNow 的 MID Server

MID Server 可让 ServiceNow 与网络内部的资源通信。

MID Server 架构

ServiceNow Instance
    ↓ ECC Queue
MID Server
    ├── Probes (Outbound)
    │   └── Commands sent TO MID
    ├── Sensors (Inbound)
    │   └── Results sent FROM MID
    └── Script Execution

关键表

表用途
ecc_agentMID Server 记录
ecc_queue输入/输出队列
discovery_probes探测定义
discovery_sensors传感器定义
sys_script_execution脚本执行请求

ECC 队列通信(ES5)

向 MID Server 发送命令
// Send command via ECC queue (ES5 ONLY!)
function sendMIDCommand(midServerName, command, parameters) {
  var mid = getMIDServer(midServerName)
  if (!mid) {
    gs.error("MID Server not found: " + midServerName)
    return null
  }

  var ecc = new GlideRecord("ecc_queue")
  ecc.initialize()

  // ECC Queue settings
  ecc.setValue("agent", mid.getUniqueValue())
  ecc.setValue("topic", "Command")
  ecc.setValue("name", command)
  ecc.setValue("source", "CustomScript")

  // Parameters as payload
  ecc.setValue("payload", buildPayload(parameters))

  // Direction: output = to MID, input = from MID
  ecc.setValue("queue", "output")

  // State
  ecc.setValue("state", "ready")

  return ecc.insert()
}

function getMIDServer(name) {
  var mid = new GlideRecord("ecc_agent")
  mid.addQuery("name", name)
  mid.addQuery("status", "Up")
  mid.query()
  if (mid.next()) {
    return mid
  }
  return null
}

function buildPayload(params) {
  var xml = '<?xml version="1.0" encoding="UTF-8"?>'
  xml += "<parameters>"
  for (var key in params) {
    if (params.hasOwnProperty(key)) {
      xml += '<parameter name="' + key + '">'
      xml += "<value>" + escapeXML(params[key]) + "</value>"
      xml += "</parameter>"
    }
  }
  xml += "</parameters>"
  return xml
}

function escapeXML(str) {
  return str
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&apos;")
}
监控 ECC 响应
// Wait for ECC queue response (ES5 ONLY!)
function waitForECCResponse(eccSysId, timeoutSeconds) {
  var startTime = new Date().getTime()
  var timeout = timeoutSeconds * 1000

  while (true) {
    // Check for response
    var response = new GlideRecord("ecc_queue")
    response.addQuery("response_to", eccSysId)
    response.addQuery("queue", "input")
    response.query()

    if (response.next()) {
      return {
        success: response.getValue("state") === "processed",
        payload: response.getValue("payload"),
        error: response.getValue("error_string"),
      }
    }

    // Check timeout
    if (new Date().getTime() - startTime > timeout) {
      return {
        success: false,
        error: "Timeout waiting for MID response",
      }
    }

    // Wait before retry
    gs.sleep(1000)
  }
}

MID Server 脚本(ES5)

在 MID 上执行脚本
// Execute JavaScript on MID Server (ES5 ONLY!)
function executeMIDScript(midServerName, script) {
  var mid = getMIDServer(midServerName)
  if (!mid) {
    return { success: false, error: "MID Server not found" }
  }

  var ecc = new GlideRecord("ecc_queue")
  ecc.initialize()
  ecc.setValue("agent", mid.getUniqueValue())
  ecc.setValue("topic", "JSProbe")
  ecc.setValue("name", "Custom Script Execution")

  // Script payload
  var payload = '<?xml version="1.0" encoding="UTF-8"?>'
  payload += "<parameters>"
  payload += '<parameter name="script"><value><![CDATA[' + script + "]]></value></parameter>"
  payload += "</parameters>"

  ecc.setValue("payload", payload)
  ecc.setValue("queue", "output")
  ecc.setValue("state", "ready")

  var eccSysId = ecc.insert()

  return {
    success: true,
    ecc_sys_id: eccSysId,
  }
}

// Example: Check disk space on remote server
var diskCheckScript = [
  "var output = {};",
  "try {",
  '    var cmd = "df -h /";',
  "    var result = Packages.com.service_now.mid.probe.tpcon.OperatingSystemCommand.execute(cmd);",
  "    output.disk_info = result.getOutput();",
  "    output.success = true;",
  "} catch (e) {",
  "    output.success = false;",
  "    output.error = e.message;",
  "}",
  "output;",
].join("\n")

自定义探测(ES5)

创建探测
// Create custom probe (ES5 ONLY!)
var probe = new GlideRecord("discovery_probes")
probe.initialize()

probe.setValue("name", "Custom Application Status")
probe.setValue("short_description", "Check custom application status")
probe.setValue("active", true)

// Probe type
probe.setValue("mid_type", "probe")

// Trigger type
probe.setValue("triggered_by", "on_demand")

// Probe script (runs on MID Server - ES5/Rhino!)
probe.setValue(
  "script",
  "var output = {};\n" +
    "\n" +
    "// Get parameters\n" +
    'var host = probe.getParameter("host");\n' +
    'var port = probe.getParameter("port");\n' +
    "\n" +
    "try {\n" +
    "    // Execute health check\n" +
    '    var url = "http://" + host + ":" + port + "/health";\n' +
    "    var conn = new java.net.URL(url).openConnection();\n" +
    '    conn.setRequestMethod("GET");\n' +
    "    conn.setConnectTimeout(5000);\n" +
    "    conn.setReadTimeout(5000);\n" +
    "    \n" +
    "    var responseCode = conn.getResponseCode();\n" +
    '    output.status = (responseCode === 200) ? "healthy" : "unhealthy";\n' +
    "    output.response_code = responseCode;\n" +
    "    output.success = true;\n" +
    "} catch (e) {\n" +
    '    output.status = "unreachable";\n' +
    "    output.error = e.message;\n" +
    "    output.success = false;\n" +
    "}\n" +
    "\n" +
    "output;",
)

probe.insert()
创建传感器
// Create sensor to process probe results (ES5 ONLY!)
var sensor = new GlideRecord("discovery_sensors")
sensor.initialize()

sensor.setValue("name", "Process Application Status")
sensor.setValue("short_description", "Process custom application status results")
sensor.setValue("active", true)

// Link to probe
sensor.setValue("triggered_by", probeSysId)

// Sensor script (runs on ServiceNow instance - ES5!)
sensor.setValue(
  "script",
  "(function process(result, source) {\n" +
    "    var output = JSON.parse(result.output);\n" +
    "    \n" +
    "    // Find or create application CI\n" +
    '    var appCI = new GlideRecord("cmdb_ci_appl");\n' +
    '    appCI.addQuery("name", source.getParameter("app_name"));\n' +
    "    appCI.query();\n" +
    "    \n" +
    "    if (!appCI.next()) {\n" +
    "        appCI.initialize();\n" +
    '        appCI.name = source.getParameter("app_name");\n' +
    "        appCI.insert();\n" +
    "    }\n" +
    "    \n" +
    "    // Update status\n" +
    "    appCI.u_health_status = output.status;\n" +
    "    appCI.u_last_health_check = new GlideDateTime();\n" +
    "    appCI.update();\n" +
    "    \n" +
    "    // Create event if unhealthy\n" +
    '    if (output.status !== "healthy") {\n' +
    "        createHealthAlert(appCI, output);\n" +
    "    }\n" +
    "})(result, source);",
)

sensor.insert()

编排(ES5)

远程 PowerShell
// Execute PowerShell on Windows server (ES5 ONLY!)
function executeRemotePowerShell(midServerName, targetHost, script, credential) {
  var payload = [
    '<?xml version="1.0" encoding="UTF-8"?>',
    "<parameters>",
    '  <parameter name="host"><value>' + targetHost + "</value></parameter>",
    '  <parameter name="credential_id"><value>' + credential + "</value></parameter>",
    '  <parameter name="script"><value><![CDATA[' + script + "]]></value></parameter>",
    "</parameters>",
  ].join("\n")

  var mid = getMIDServer(midServerName)
  if (!mid) {
    return { success: false, error: "MID Server not found" }
  }

  var ecc = new GlideRecord("ecc_queue")
  ecc.initialize()
  ecc.setValue("agent", mid.getUniqueValue())
  ecc.setValue("topic", "PowerShell")
  ecc.setValue("name", "Remote PowerShell Execution")
  ecc.setValue("payload", payload)
  ecc.setValue("queue", "output")
  ecc.setValue("state", "ready")

  return {
    success: true,
    ecc_sys_id: ecc.insert(),
  }
}
远程 SSH
// Execute SSH command (ES5 ONLY!)
function executeRemoteSSH(midServerName, targetHost, command, credential) {
  var payload = [
    '<?xml version="1.0" encoding="UTF-8"?>',
    "<parameters>",
    '  <parameter name="host"><value>' + targetHost + "</value></parameter>",
    '  <parameter name="credential_id"><value>' + credential + "</value></parameter>",
    '  <parameter name="command"><value>' + escapeXML(command) + "</value></parameter>",
    "</parameters>",
  ].join("\n")

  var mid = getMIDServer(midServerName)
  if (!mid) {
    return { success: false, error: "MID Server not found" }
  }

  var ecc = new GlideRecord("ecc_queue")
  ecc.initialize()
  ecc.setValue("agent", mid.getUniqueValue())
  ecc.setValue("topic", "SSHCommand")
  ecc.setValue("name", "Remote SSH Execution")
  ecc.setValue("payload", payload)
  ecc.setValue("queue", "output")
  ecc.setValue("state", "ready")

  return {
    success: true,
    ecc_sys_id: ecc.insert(),
  }
}

MID Server 监控(ES5)

检查 MID 状态
// Get MID Server status (ES5 ONLY!)
function getMIDServerStatus() {
  var servers = []

  var mid = new GlideRecord("ecc_agent")
  mid.addQuery("status", "!=", "Decommissioned")
  mid.query()

  while (mid.next()) {
    servers.push({
      name: mid.getValue("name"),
      status: mid.getValue("status"),
      ip: mid.getValue("ip_address"),
      version: mid.getValue("version"),
      validated: mid.getValue("validated"),
      last_refreshed: mid.getValue("last_refreshed"),
      host_name: mid.getValue("host_name"),
    })
  }

  return servers
}

MCP 工具集成

可用工具
工具用途
snow_query_table查询 MID 和 ECC 表
snow_artifact_manage (action='find')查找探测/传感器
snow_execute_script测试 MID 脚本
示例工作流
// 1. Check MID Server status
await snow_query_table({
  table: "ecc_agent",
  query: "status=Up",
  fields: "name,ip_address,version,last_refreshed",
})

// 2. Query ECC queue
await snow_query_table({
  table: "ecc_queue",
  query: "queue=output^state=ready",
  fields: "agent,topic,name,state,sys_created_on",
})

// 3. Find probes
await snow_query_table({
  table: "discovery_probes",
  query: "active=true",
  fields: "name,short_description,mid_type",
})

最佳实践

  1. 凭据 - 切勿在脚本中硬编码
  2. 错误处理 - 处理网络故障
  3. 超时 - 设置适当的超时时间
  4. 日志记录 - 记录日志以便排查问题
  5. 安全性 - 限制 MID 的访问权限
  6. 监控 - 跟踪 MID 的运行状况
  7. 负载均衡 - 使用多个 MID 实现高可用性
  8. 仅限 ES5 - 不使用现代 JavaScript 语法

评论

支持 Markdown