@renanlido/tia-openness-mcp 1.1.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +396 -396
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -30989,7 +30989,7 @@ async function tiaFetch(path, init = {}, opts = {}) {
|
|
|
30989
30989
|
} catch (cause) {
|
|
30990
30990
|
const isTimeout = cause instanceof Error && (cause.name === "AbortError" || cause.name === "TimeoutError");
|
|
30991
30991
|
throw new TiaApiError(
|
|
30992
|
-
isTimeout ? `
|
|
30992
|
+
isTimeout ? `CLIENT timeout after ${timeout}ms waiting for ${BASE}${path}. The host is NOT necessarily unreachable: the operation may STILL be running on serve (a slow Openness operation, or the serial worker busy with a previous call). Increase TIA_SLOW_TIMEOUT_MS/TIA_API_TIMEOUT_MS or retry; before repeating a create/compile, check the state first (the 1st attempt may have completed).` : `Could not connect to the TIA API at ${BASE}. Is 'serve' running and reachable from this machine?`,
|
|
30993
30993
|
{ kind: isTimeout ? "timeout" : "connection_refused", cause }
|
|
30994
30994
|
);
|
|
30995
30995
|
} finally {
|
|
@@ -31020,17 +31020,17 @@ async function tiaFetch(path, init = {}, opts = {}) {
|
|
|
31020
31020
|
function hintFor(err) {
|
|
31021
31021
|
switch (err.kind) {
|
|
31022
31022
|
case "timeout":
|
|
31023
|
-
return "
|
|
31023
|
+
return "The operation may STILL be running on serve (serial worker). Increase TIA_SLOW_TIMEOUT_MS; only investigate connectivity (IP/port/firewall/VM) if GET /health also fails.";
|
|
31024
31024
|
case "connection_refused":
|
|
31025
|
-
return "
|
|
31025
|
+
return "Start the API on the serve host: `TIAOpenness.exe serve 5000 --host 0.0.0.0` and check TIA_API_BASE.";
|
|
31026
31026
|
case "license_required":
|
|
31027
|
-
return "
|
|
31027
|
+
return "Server not activated: configure the API key in the TIAOpenness GUI ('License' tab).";
|
|
31028
31028
|
case "not_connected":
|
|
31029
|
-
return "
|
|
31029
|
+
return "No project connected \u2014 connect/open a project before this operation.";
|
|
31030
31030
|
case "not_found":
|
|
31031
|
-
return "
|
|
31031
|
+
return "Resource not found \u2014 rediscover it via a listing tool.";
|
|
31032
31032
|
}
|
|
31033
|
-
if (err.status === 403) return "
|
|
31033
|
+
if (err.status === 403) return "Server not activated \u2014 configure the license in the TIAOpenness GUI.";
|
|
31034
31034
|
return null;
|
|
31035
31035
|
}
|
|
31036
31036
|
function textResult(payload, isError = false) {
|
|
@@ -31055,8 +31055,8 @@ function registerReadOnlyTools(server2) {
|
|
|
31055
31055
|
server2.registerTool(
|
|
31056
31056
|
"tia_instances",
|
|
31057
31057
|
{
|
|
31058
|
-
title: "TIA \u2014
|
|
31059
|
-
description: "
|
|
31058
|
+
title: "TIA \u2014 running instances",
|
|
31059
|
+
description: "Lists the TIA Portal sessions/instances running on the serve host (PID, mode, project path). Maps to GET /instances. Read-only (class R).",
|
|
31060
31060
|
inputSchema: {}
|
|
31061
31061
|
},
|
|
31062
31062
|
async () => getResult("/instances")
|
|
@@ -31064,8 +31064,8 @@ function registerReadOnlyTools(server2) {
|
|
|
31064
31064
|
server2.registerTool(
|
|
31065
31065
|
"tia_status",
|
|
31066
31066
|
{
|
|
31067
|
-
title: "TIA \u2014 status
|
|
31068
|
-
description: "
|
|
31067
|
+
title: "TIA \u2014 connection status",
|
|
31068
|
+
description: "Current status of serve's connection to TIA Portal (attached instance, active project). Maps to GET /tia. Read-only (class R).",
|
|
31069
31069
|
inputSchema: {}
|
|
31070
31070
|
},
|
|
31071
31071
|
async () => getResult("/tia")
|
|
@@ -31073,10 +31073,10 @@ function registerReadOnlyTools(server2) {
|
|
|
31073
31073
|
server2.registerTool(
|
|
31074
31074
|
"tia_projects",
|
|
31075
31075
|
{
|
|
31076
|
-
title: "TIA \u2014
|
|
31077
|
-
description: "
|
|
31076
|
+
title: "TIA \u2014 projects in a folder",
|
|
31077
|
+
description: "Lists TIA project files (.ap*) in a folder on the serve host. Maps to GET /tia/projects?folder=<folder>. Read-only (class R).",
|
|
31078
31078
|
inputSchema: {
|
|
31079
|
-
folder: external_exports.string().describe("
|
|
31079
|
+
folder: external_exports.string().describe("path of the folder to scan on the serve host (required)")
|
|
31080
31080
|
}
|
|
31081
31081
|
},
|
|
31082
31082
|
async ({ folder }) => getResult(`/tia/projects?folder=${encodeURIComponent(folder)}`)
|
|
@@ -31084,8 +31084,8 @@ function registerReadOnlyTools(server2) {
|
|
|
31084
31084
|
server2.registerTool(
|
|
31085
31085
|
"tia_project_info",
|
|
31086
31086
|
{
|
|
31087
|
-
title: "TIA \u2014
|
|
31088
|
-
description: "
|
|
31087
|
+
title: "TIA \u2014 active project info",
|
|
31088
|
+
description: "Information about the currently connected project (name, path, author). Requires a connected project. Maps to GET /project. Read-only (class R).",
|
|
31089
31089
|
inputSchema: {}
|
|
31090
31090
|
},
|
|
31091
31091
|
async () => getResult("/project")
|
|
@@ -31093,8 +31093,8 @@ function registerReadOnlyTools(server2) {
|
|
|
31093
31093
|
server2.registerTool(
|
|
31094
31094
|
"tia_project_languages",
|
|
31095
31095
|
{
|
|
31096
|
-
title: "TIA \u2014
|
|
31097
|
-
description: "
|
|
31096
|
+
title: "TIA \u2014 project languages",
|
|
31097
|
+
description: "Lists the languages (cultures) configured in the active project. Requires a connected project. Maps to GET /project/languages. Read-only (class R).",
|
|
31098
31098
|
inputSchema: {}
|
|
31099
31099
|
},
|
|
31100
31100
|
async () => getResult("/project/languages")
|
|
@@ -31102,8 +31102,8 @@ function registerReadOnlyTools(server2) {
|
|
|
31102
31102
|
server2.registerTool(
|
|
31103
31103
|
"tia_plcs",
|
|
31104
31104
|
{
|
|
31105
|
-
title: "TIA \u2014
|
|
31106
|
-
description: "
|
|
31105
|
+
title: "TIA \u2014 list of PLCs",
|
|
31106
|
+
description: "Lists the PLCs (PlcSoftware) of the active project. Requires a connected project. Maps to GET /plcs. Read-only (class R).",
|
|
31107
31107
|
inputSchema: {}
|
|
31108
31108
|
},
|
|
31109
31109
|
async () => getResult("/plcs")
|
|
@@ -31111,8 +31111,8 @@ function registerReadOnlyTools(server2) {
|
|
|
31111
31111
|
server2.registerTool(
|
|
31112
31112
|
"tia_devices",
|
|
31113
31113
|
{
|
|
31114
|
-
title: "TIA \u2014
|
|
31115
|
-
description: "
|
|
31114
|
+
title: "TIA \u2014 list of devices",
|
|
31115
|
+
description: "Lists the project's devices and their items. Requires a connected project. Maps to GET /devices. Read-only (class R).",
|
|
31116
31116
|
inputSchema: {}
|
|
31117
31117
|
},
|
|
31118
31118
|
async () => getResult("/devices")
|
|
@@ -31120,10 +31120,10 @@ function registerReadOnlyTools(server2) {
|
|
|
31120
31120
|
server2.registerTool(
|
|
31121
31121
|
"tia_device_tree",
|
|
31122
31122
|
{
|
|
31123
|
-
title: "TIA \u2014
|
|
31124
|
-
description: "
|
|
31123
|
+
title: "TIA \u2014 device tree",
|
|
31124
|
+
description: "Hardware tree of a device (racks/slots/modules). Requires a connected project. Maps to GET /devices/{device}/tree. Read-only (class R).",
|
|
31125
31125
|
inputSchema: {
|
|
31126
|
-
device: external_exports.string().describe("
|
|
31126
|
+
device: external_exports.string().describe("device name")
|
|
31127
31127
|
}
|
|
31128
31128
|
},
|
|
31129
31129
|
async ({ device }) => getResult(`/devices/${seg(device)}/tree`)
|
|
@@ -31131,10 +31131,10 @@ function registerReadOnlyTools(server2) {
|
|
|
31131
31131
|
server2.registerTool(
|
|
31132
31132
|
"tia_device_connections",
|
|
31133
31133
|
{
|
|
31134
|
-
title: "TIA \u2014
|
|
31135
|
-
description: "
|
|
31134
|
+
title: "TIA \u2014 device connections",
|
|
31135
|
+
description: "Lists the communication connections (S7 etc.) of a device. Requires a connected project. Maps to GET /devices/{device}/connections. Read-only (class R).",
|
|
31136
31136
|
inputSchema: {
|
|
31137
|
-
device: external_exports.string().describe("
|
|
31137
|
+
device: external_exports.string().describe("device name")
|
|
31138
31138
|
}
|
|
31139
31139
|
},
|
|
31140
31140
|
async ({ device }) => getResult(`/devices/${seg(device)}/connections`)
|
|
@@ -31142,10 +31142,10 @@ function registerReadOnlyTools(server2) {
|
|
|
31142
31142
|
server2.registerTool(
|
|
31143
31143
|
"tia_plc_blocks",
|
|
31144
31144
|
{
|
|
31145
|
-
title: "TIA \u2014
|
|
31146
|
-
description: "
|
|
31145
|
+
title: "TIA \u2014 blocks of a PLC",
|
|
31146
|
+
description: "Lists the blocks of a PLC (name, type, language, number, isConsistent, isKnowHowProtected). Requires a connected project. Maps to GET /plcs/{plc}/blocks. Read-only (class R).",
|
|
31147
31147
|
inputSchema: {
|
|
31148
|
-
plc: external_exports.string().describe("
|
|
31148
|
+
plc: external_exports.string().describe("PLC name")
|
|
31149
31149
|
}
|
|
31150
31150
|
},
|
|
31151
31151
|
async ({ plc }) => getResult(`/plcs/${seg(plc)}/blocks`)
|
|
@@ -31153,10 +31153,10 @@ function registerReadOnlyTools(server2) {
|
|
|
31153
31153
|
server2.registerTool(
|
|
31154
31154
|
"tia_plc_types",
|
|
31155
31155
|
{
|
|
31156
|
-
title: "TIA \u2014
|
|
31157
|
-
description: "
|
|
31156
|
+
title: "TIA \u2014 types (UDTs) of a PLC",
|
|
31157
|
+
description: "Lists the user data types (UDTs) of a PLC. Requires a connected project. Maps to GET /plcs/{plc}/types. Read-only (class R).",
|
|
31158
31158
|
inputSchema: {
|
|
31159
|
-
plc: external_exports.string().describe("
|
|
31159
|
+
plc: external_exports.string().describe("PLC name")
|
|
31160
31160
|
}
|
|
31161
31161
|
},
|
|
31162
31162
|
async ({ plc }) => getResult(`/plcs/${seg(plc)}/types`)
|
|
@@ -31164,10 +31164,10 @@ function registerReadOnlyTools(server2) {
|
|
|
31164
31164
|
server2.registerTool(
|
|
31165
31165
|
"tia_plc_tags",
|
|
31166
31166
|
{
|
|
31167
|
-
title: "TIA \u2014
|
|
31168
|
-
description: "
|
|
31167
|
+
title: "TIA \u2014 tag tables of a PLC",
|
|
31168
|
+
description: "Lists the tag tables and their tags for a PLC. Requires a connected project. Maps to GET /plcs/{plc}/tags. Read-only (class R).",
|
|
31169
31169
|
inputSchema: {
|
|
31170
|
-
plc: external_exports.string().describe("
|
|
31170
|
+
plc: external_exports.string().describe("PLC name")
|
|
31171
31171
|
}
|
|
31172
31172
|
},
|
|
31173
31173
|
async ({ plc }) => getResult(`/plcs/${seg(plc)}/tags`)
|
|
@@ -31175,10 +31175,10 @@ function registerReadOnlyTools(server2) {
|
|
|
31175
31175
|
server2.registerTool(
|
|
31176
31176
|
"tia_plc_watchtables",
|
|
31177
31177
|
{
|
|
31178
|
-
title: "TIA \u2014 watch tables
|
|
31179
|
-
description: "
|
|
31178
|
+
title: "TIA \u2014 watch tables of a PLC",
|
|
31179
|
+
description: "Lists the watch tables of a PLC. Requires a connected project. Maps to GET /plcs/{plc}/watchtables. Read-only (class R).",
|
|
31180
31180
|
inputSchema: {
|
|
31181
|
-
plc: external_exports.string().describe("
|
|
31181
|
+
plc: external_exports.string().describe("PLC name")
|
|
31182
31182
|
}
|
|
31183
31183
|
},
|
|
31184
31184
|
async ({ plc }) => getResult(`/plcs/${seg(plc)}/watchtables`)
|
|
@@ -31186,12 +31186,12 @@ function registerReadOnlyTools(server2) {
|
|
|
31186
31186
|
server2.registerTool(
|
|
31187
31187
|
"tia_catalog",
|
|
31188
31188
|
{
|
|
31189
|
-
title: "TIA \u2014
|
|
31190
|
-
description: "
|
|
31189
|
+
title: "TIA \u2014 search the hardware catalog",
|
|
31190
|
+
description: "Searches the hardware catalog (article number, type identifier, version). Requires TIA connected. By default the (long) 'description' is OMITTED \u2014 on broad filters it blows up the payload (description \xD7 firmware variants); pass verbose:true WITH a specific filter to include it. Maps to GET /catalog?filter=&typeIdentifier=&verbose=. Read-only (R).",
|
|
31191
31191
|
inputSchema: {
|
|
31192
|
-
filter: external_exports.string().describe("
|
|
31193
|
-
typeIdentifier: external_exports.string().describe("type identifier
|
|
31194
|
-
verbose: external_exports.boolean().describe("
|
|
31192
|
+
filter: external_exports.string().describe("filter text: article no., description, etc. (optional)").optional(),
|
|
31193
|
+
typeIdentifier: external_exports.string().describe("type identifier to filter by (optional)").optional(),
|
|
31194
|
+
verbose: external_exports.boolean().describe("include the full 'description' (off by default; on broad filters it blows up the payload \u2014 use with a specific filter)").optional()
|
|
31195
31195
|
}
|
|
31196
31196
|
},
|
|
31197
31197
|
async ({ filter, typeIdentifier, verbose }) => {
|
|
@@ -31206,11 +31206,11 @@ function registerReadOnlyTools(server2) {
|
|
|
31206
31206
|
server2.registerTool(
|
|
31207
31207
|
"tia_connections_diagnose",
|
|
31208
31208
|
{
|
|
31209
|
-
title: "TIA \u2014
|
|
31210
|
-
description: "
|
|
31209
|
+
title: "TIA \u2014 S7 connection diagnostics",
|
|
31210
|
+
description: "Diagnostic for an S7 connection between two devices: available interfaces, nodes, and creationinfos. Requires a connected project. Maps to GET /connections/diagnose?localDevice=&partnerDevice= (both required). Read-only (class R).",
|
|
31211
31211
|
inputSchema: {
|
|
31212
|
-
localDevice: external_exports.string().describe("
|
|
31213
|
-
partnerDevice: external_exports.string().describe("
|
|
31212
|
+
localDevice: external_exports.string().describe("local device name (required)"),
|
|
31213
|
+
partnerDevice: external_exports.string().describe("partner device name (required)")
|
|
31214
31214
|
}
|
|
31215
31215
|
},
|
|
31216
31216
|
async ({ localDevice, partnerDevice }) => getResult(`/connections/diagnose?localDevice=${encodeURIComponent(localDevice)}&partnerDevice=${encodeURIComponent(partnerDevice)}`)
|
|
@@ -31218,8 +31218,8 @@ function registerReadOnlyTools(server2) {
|
|
|
31218
31218
|
server2.registerTool(
|
|
31219
31219
|
"tia_subnets",
|
|
31220
31220
|
{
|
|
31221
|
-
title: "TIA \u2014
|
|
31222
|
-
description: "
|
|
31221
|
+
title: "TIA \u2014 list of subnets",
|
|
31222
|
+
description: "Lists the active project's subnets. Requires a connected project. Maps to GET /subnets. Read-only (class R).",
|
|
31223
31223
|
inputSchema: {}
|
|
31224
31224
|
},
|
|
31225
31225
|
async () => getResult("/subnets")
|
|
@@ -31227,8 +31227,8 @@ function registerReadOnlyTools(server2) {
|
|
|
31227
31227
|
server2.registerTool(
|
|
31228
31228
|
"tia_obj_roots",
|
|
31229
31229
|
{
|
|
31230
|
-
title: "TIA \u2014
|
|
31231
|
-
description: "Handles
|
|
31230
|
+
title: "TIA \u2014 object model roots",
|
|
31231
|
+
description: "Handles of the roots of the generic object model (project, devices, subnets). Requires a connected project. Maps to GET /obj/roots. Read-only (class R).",
|
|
31232
31232
|
inputSchema: {}
|
|
31233
31233
|
},
|
|
31234
31234
|
async () => getResult("/obj/roots")
|
|
@@ -31236,10 +31236,10 @@ function registerReadOnlyTools(server2) {
|
|
|
31236
31236
|
server2.registerTool(
|
|
31237
31237
|
"tia_obj_get",
|
|
31238
31238
|
{
|
|
31239
|
-
title: "TIA \u2014
|
|
31240
|
-
description: "
|
|
31239
|
+
title: "TIA \u2014 object by handle",
|
|
31240
|
+
description: "Details of an object by handle (type, name, attributes, compositions). Requires a connected project. Maps to GET /obj/{handle}. Read-only (class R).",
|
|
31241
31241
|
inputSchema: {
|
|
31242
|
-
handle: external_exports.string().describe("handle
|
|
31242
|
+
handle: external_exports.string().describe("integer handle of the object (obtained from /obj/roots or /obj/{h}/items/{comp})")
|
|
31243
31243
|
}
|
|
31244
31244
|
},
|
|
31245
31245
|
async ({ handle }) => getResult(`/obj/${seg(handle)}`)
|
|
@@ -31247,11 +31247,11 @@ function registerReadOnlyTools(server2) {
|
|
|
31247
31247
|
server2.registerTool(
|
|
31248
31248
|
"tia_obj_items",
|
|
31249
31249
|
{
|
|
31250
|
-
title: "TIA \u2014
|
|
31251
|
-
description: "Handles
|
|
31250
|
+
title: "TIA \u2014 children of a composition",
|
|
31251
|
+
description: "Handles of an object's children in a composition. Requires a connected project. Maps to GET /obj/{handle}/items/{composition}. Read-only (class R).",
|
|
31252
31252
|
inputSchema: {
|
|
31253
|
-
handle: external_exports.string().describe("handle
|
|
31254
|
-
composition: external_exports.string().describe("
|
|
31253
|
+
handle: external_exports.string().describe("integer handle of the parent object"),
|
|
31254
|
+
composition: external_exports.string().describe("name of the composition to enumerate")
|
|
31255
31255
|
}
|
|
31256
31256
|
},
|
|
31257
31257
|
async ({ handle, composition }) => getResult(`/obj/${seg(handle)}/items/${seg(composition)}`)
|
|
@@ -31259,10 +31259,10 @@ function registerReadOnlyTools(server2) {
|
|
|
31259
31259
|
server2.registerTool(
|
|
31260
31260
|
"tia_obj_info",
|
|
31261
31261
|
{
|
|
31262
|
-
title: "TIA \u2014 info
|
|
31263
|
-
description: "
|
|
31262
|
+
title: "TIA \u2014 object info",
|
|
31263
|
+
description: "Available compositions and invocations of an object. Requires a connected project. Maps to GET /obj/{handle}/info. Read-only (class R).",
|
|
31264
31264
|
inputSchema: {
|
|
31265
|
-
handle: external_exports.string().describe("handle
|
|
31265
|
+
handle: external_exports.string().describe("integer handle of the object")
|
|
31266
31266
|
}
|
|
31267
31267
|
},
|
|
31268
31268
|
async ({ handle }) => getResult(`/obj/${seg(handle)}/info`)
|
|
@@ -31270,11 +31270,11 @@ function registerReadOnlyTools(server2) {
|
|
|
31270
31270
|
server2.registerTool(
|
|
31271
31271
|
"tia_obj_creationinfos",
|
|
31272
31272
|
{
|
|
31273
|
-
title: "TIA \u2014
|
|
31274
|
-
description: "
|
|
31273
|
+
title: "TIA \u2014 creation info for a composition",
|
|
31274
|
+
description: "Creatable types in a composition and their parameters (mandatory/supported types). Requires a connected project. Maps to GET /obj/{handle}/creationinfos/{composition}. Read-only (class R).",
|
|
31275
31275
|
inputSchema: {
|
|
31276
|
-
handle: external_exports.string().describe("handle
|
|
31277
|
-
composition: external_exports.string().describe("
|
|
31276
|
+
handle: external_exports.string().describe("integer handle of the parent object"),
|
|
31277
|
+
composition: external_exports.string().describe("composition name")
|
|
31278
31278
|
}
|
|
31279
31279
|
},
|
|
31280
31280
|
async ({ handle, composition }) => getResult(`/obj/${seg(handle)}/creationinfos/${seg(composition)}`)
|
|
@@ -31282,10 +31282,10 @@ function registerReadOnlyTools(server2) {
|
|
|
31282
31282
|
server2.registerTool(
|
|
31283
31283
|
"tia_obj_services",
|
|
31284
31284
|
{
|
|
31285
|
-
title: "TIA \u2014
|
|
31286
|
-
description: "
|
|
31285
|
+
title: "TIA \u2014 services of an object",
|
|
31286
|
+
description: "Lists the services (GetService<T>) available on an object. Requires a connected project. Maps to GET /obj/{handle}/services. Read-only (class R).",
|
|
31287
31287
|
inputSchema: {
|
|
31288
|
-
handle: external_exports.string().describe("handle
|
|
31288
|
+
handle: external_exports.string().describe("integer handle of the object")
|
|
31289
31289
|
}
|
|
31290
31290
|
},
|
|
31291
31291
|
async ({ handle }) => getResult(`/obj/${seg(handle)}/services`)
|
|
@@ -31335,11 +31335,11 @@ function trustHandoff(projectPath, err) {
|
|
|
31335
31335
|
gate: "trust_dialog",
|
|
31336
31336
|
state: "WAITING_FOR_TRUST",
|
|
31337
31337
|
canDo: `connect ${projectPath}`,
|
|
31338
|
-
youMustDo: '
|
|
31338
|
+
youMustDo: 'A human needs to confirm the TIA Openness TRUST/SECURITY dialog ON THE SERVE HOST (click "Sim, para tudo" / "Yes to all"). It is required on the 1st connection of each `serve` process and CANNOT be automated (for security reasons).',
|
|
31339
31339
|
nextSteps: [
|
|
31340
|
-
"1.
|
|
31341
|
-
"2.
|
|
31342
|
-
"3. Re-
|
|
31340
|
+
"1. If TIA is headless, call tia_show_ui to relaunch it VISIBLE and render the dialog on screen.",
|
|
31341
|
+
"2. Ask a human to confirm the trust dialog on the serve host.",
|
|
31342
|
+
"3. Re-call tia_connect with the SAME projectPath and this resumeToken."
|
|
31343
31343
|
],
|
|
31344
31344
|
blockingError: err.message,
|
|
31345
31345
|
resumeToken
|
|
@@ -31376,10 +31376,10 @@ function registerLifecycleTools(server2) {
|
|
|
31376
31376
|
server2.registerTool(
|
|
31377
31377
|
"tia_start",
|
|
31378
31378
|
{
|
|
31379
|
-
title: "TIA \u2014
|
|
31380
|
-
description: "
|
|
31379
|
+
title: "TIA \u2014 start/attach (no project)",
|
|
31380
|
+
description: "Starts TIA Portal (or attaches to an idle instance) WITHOUT opening a project. Class M-off (offline mutation). `headless` only applies when CREATING a new instance (when attaching, it inherits the existing mode). Step 1 of the proactive trust-GATE flow: tia_start \u2192 tia_show_ui \u2192 tia_connect. Maps to POST /tia/start.",
|
|
31381
31381
|
inputSchema: {
|
|
31382
|
-
headless: external_exports.boolean().optional().describe("true =
|
|
31382
|
+
headless: external_exports.boolean().optional().describe("true = no window (fast offline authoring); false (default) = with window. Only when creating a new instance.")
|
|
31383
31383
|
}
|
|
31384
31384
|
},
|
|
31385
31385
|
async ({ headless }) => postResult("/tia/start", jsonBody({ headless }))
|
|
@@ -31387,8 +31387,8 @@ function registerLifecycleTools(server2) {
|
|
|
31387
31387
|
server2.registerTool(
|
|
31388
31388
|
"tia_show_ui",
|
|
31389
31389
|
{
|
|
31390
|
-
title: "TIA \u2014
|
|
31391
|
-
description: "
|
|
31390
|
+
title: "TIA \u2014 make visible (enables the trust GATE)",
|
|
31391
|
+
description: "Relaunches the HEADLESS instance we started as VISIBLE, reopening the same project, to RENDER the 1st-connection trust dialog on screen (the concrete handoff of GATE G1) \u2014 so a human can confirm it. Only works if serve owns the portal (not on an attached instance). Maps to POST /tia/show-ui. Use BEFORE tia_connect when you started headless.",
|
|
31392
31392
|
inputSchema: {}
|
|
31393
31393
|
},
|
|
31394
31394
|
async () => postResult("/tia/show-ui")
|
|
@@ -31396,15 +31396,15 @@ function registerLifecycleTools(server2) {
|
|
|
31396
31396
|
server2.registerTool(
|
|
31397
31397
|
"tia_connect",
|
|
31398
31398
|
{
|
|
31399
|
-
title: "TIA \u2014
|
|
31400
|
-
description: "
|
|
31399
|
+
title: "TIA \u2014 connect/open project (trust GATE G1)",
|
|
31400
|
+
description: "Opens/attaches a TIA project (.ap*) on the serve host. Class M-off. WARNING: the 1st connection per `serve` process can BLOCK on the trust GATE (G1) \u2014 if the dialog hasn't been confirmed, this tool does NOT retry-storm: it returns a `requires_human_action` envelope (gate trust_dialog, with resumeToken) asking a human to confirm the dialog on the host. Proactive flow: tia_start \u2192 tia_show_ui \u2192 (human confirms) \u2192 tia_connect. UMAC (umacUser/umacPassword) is GATE G6: provide it ONLY if a human gave the credentials \u2014 NEVER make them up. Maps to POST /connect.",
|
|
31401
31401
|
inputSchema: {
|
|
31402
|
-
projectPath: external_exports.string().describe("
|
|
31403
|
-
withUserInterface: external_exports.boolean().optional().describe("
|
|
31404
|
-
umacUser: external_exports.string().optional().describe("
|
|
31405
|
-
umacPassword: external_exports.string().optional().describe("
|
|
31406
|
-
umacType: external_exports.string().optional().describe('
|
|
31407
|
-
resumeToken: external_exports.string().optional().describe("token
|
|
31402
|
+
projectPath: external_exports.string().describe("path to the project file (.ap*) on the serve host (required)"),
|
|
31403
|
+
withUserInterface: external_exports.boolean().optional().describe("open with the TIA UI visible (default true)"),
|
|
31404
|
+
umacUser: external_exports.string().optional().describe("UMAC user (GATE G6; only if a human provided it \u2014 never make it up)"),
|
|
31405
|
+
umacPassword: external_exports.string().optional().describe("UMAC password (GATE G6; only if a human provided it \u2014 never make it up)"),
|
|
31406
|
+
umacType: external_exports.string().optional().describe('UMAC credential type (default "Project")'),
|
|
31407
|
+
resumeToken: external_exports.string().optional().describe("token returned by the GATE handoff; re-call with it AFTER a human has confirmed the dialog")
|
|
31408
31408
|
}
|
|
31409
31409
|
},
|
|
31410
31410
|
async (args) => connectFlow(args)
|
|
@@ -31412,8 +31412,8 @@ function registerLifecycleTools(server2) {
|
|
|
31412
31412
|
server2.registerTool(
|
|
31413
31413
|
"tia_disconnect",
|
|
31414
31414
|
{
|
|
31415
|
-
title: "TIA \u2014
|
|
31416
|
-
description: "
|
|
31415
|
+
title: "TIA \u2014 disconnect",
|
|
31416
|
+
description: "Disconnects from TIA. WARNING (Gd3): on an ATTACHED instance, /disconnect does NOT close the project \u2014 to RELEASE the project lock use tia_project_close. Maps to POST /disconnect.",
|
|
31417
31417
|
inputSchema: {}
|
|
31418
31418
|
},
|
|
31419
31419
|
async () => postResult("/disconnect")
|
|
@@ -31421,12 +31421,12 @@ function registerLifecycleTools(server2) {
|
|
|
31421
31421
|
server2.registerTool(
|
|
31422
31422
|
"tia_project_create",
|
|
31423
31423
|
{
|
|
31424
|
-
title: "TIA \u2014
|
|
31425
|
-
description: "
|
|
31424
|
+
title: "TIA \u2014 create project",
|
|
31425
|
+
description: "Creates a new TIA project. Guard Gd4: the target directory must be EMPTY \u2014 if it isn't, serve returns 409 conflict (this tool passes the error through; rediscover/choose another directory). Maps to POST /project/create.",
|
|
31426
31426
|
inputSchema: {
|
|
31427
|
-
directory: external_exports.string().describe("
|
|
31428
|
-
name: external_exports.string().describe("
|
|
31429
|
-
withUserInterface: external_exports.boolean().optional().describe("
|
|
31427
|
+
directory: external_exports.string().describe("target directory (must be empty \u2014 Gd4) (required)"),
|
|
31428
|
+
name: external_exports.string().describe("project name (required)"),
|
|
31429
|
+
withUserInterface: external_exports.boolean().optional().describe("create with the TIA UI visible (default true)")
|
|
31430
31430
|
}
|
|
31431
31431
|
},
|
|
31432
31432
|
async ({ directory, name, withUserInterface }) => postResult("/project/create", jsonBody({ directory, name, withUserInterface }))
|
|
@@ -31434,8 +31434,8 @@ function registerLifecycleTools(server2) {
|
|
|
31434
31434
|
server2.registerTool(
|
|
31435
31435
|
"tia_project_save",
|
|
31436
31436
|
{
|
|
31437
|
-
title: "TIA \u2014
|
|
31438
|
-
description: "
|
|
31437
|
+
title: "TIA \u2014 save project",
|
|
31438
|
+
description: "Saves the open project. Maps to POST /project/save.",
|
|
31439
31439
|
inputSchema: {}
|
|
31440
31440
|
},
|
|
31441
31441
|
async () => postResult("/project/save")
|
|
@@ -31443,10 +31443,10 @@ function registerLifecycleTools(server2) {
|
|
|
31443
31443
|
server2.registerTool(
|
|
31444
31444
|
"tia_project_saveas",
|
|
31445
31445
|
{
|
|
31446
|
-
title: "TIA \u2014
|
|
31447
|
-
description: "
|
|
31446
|
+
title: "TIA \u2014 save project as",
|
|
31447
|
+
description: "Saves the open project to another directory. Maps to POST /project/saveas.",
|
|
31448
31448
|
inputSchema: {
|
|
31449
|
-
directory: external_exports.string().optional().describe("
|
|
31449
|
+
directory: external_exports.string().optional().describe("target directory for 'save as'")
|
|
31450
31450
|
}
|
|
31451
31451
|
},
|
|
31452
31452
|
async ({ directory }) => postResult("/project/saveas", jsonBody({ directory }))
|
|
@@ -31454,8 +31454,8 @@ function registerLifecycleTools(server2) {
|
|
|
31454
31454
|
server2.registerTool(
|
|
31455
31455
|
"tia_project_close",
|
|
31456
31456
|
{
|
|
31457
|
-
title: "TIA \u2014
|
|
31458
|
-
description: "
|
|
31457
|
+
title: "TIA \u2014 close project",
|
|
31458
|
+
description: "Closes the open project and RELEASES the lock (Gd3: use this, not tia_disconnect, to release the project). Maps to POST /project/close.",
|
|
31459
31459
|
inputSchema: {}
|
|
31460
31460
|
},
|
|
31461
31461
|
async () => postResult("/project/close")
|
|
@@ -31463,12 +31463,12 @@ function registerLifecycleTools(server2) {
|
|
|
31463
31463
|
server2.registerTool(
|
|
31464
31464
|
"tia_project_archive",
|
|
31465
31465
|
{
|
|
31466
|
-
title: "TIA \u2014
|
|
31467
|
-
description: "
|
|
31466
|
+
title: "TIA \u2014 archive project",
|
|
31467
|
+
description: "Archives the open project (.zap*). Maps to POST /project/archive.",
|
|
31468
31468
|
inputSchema: {
|
|
31469
|
-
directory: external_exports.string().optional().describe("
|
|
31470
|
-
name: external_exports.string().optional().describe("
|
|
31471
|
-
mode: external_exports.string().optional().describe("
|
|
31469
|
+
directory: external_exports.string().optional().describe("target directory for the archive"),
|
|
31470
|
+
name: external_exports.string().optional().describe("archive file name"),
|
|
31471
|
+
mode: external_exports.string().optional().describe("archive mode (e.g., Compressed)")
|
|
31472
31472
|
}
|
|
31473
31473
|
},
|
|
31474
31474
|
async ({ directory, name, mode }) => postResult("/project/archive", jsonBody({ directory, name, mode }))
|
|
@@ -31491,7 +31491,7 @@ function errorResult2(err) {
|
|
|
31491
31491
|
function gd5Violation(typeIdentifier) {
|
|
31492
31492
|
if (!typeIdentifier) return null;
|
|
31493
31493
|
if (/:V\d/.test(typeIdentifier)) {
|
|
31494
|
-
return `Gd5:
|
|
31494
|
+
return `Gd5: the typeIdentifier uses ':V' (drift form) before the firmware version. Use '/V' (slash) \u2014 e.g.: "OrderNumber:6ES7 511-1AK02-0AB0/V2.9". Resolve the exact value with tia_catalog.`;
|
|
31495
31495
|
}
|
|
31496
31496
|
return null;
|
|
31497
31497
|
}
|
|
@@ -31503,7 +31503,7 @@ function guardError(guard, message, context) {
|
|
|
31503
31503
|
guard,
|
|
31504
31504
|
blockedBeforeOpenness: true,
|
|
31505
31505
|
context,
|
|
31506
|
-
hint: "
|
|
31506
|
+
hint: "Fix the input and try again \u2014 nothing was changed in the project."
|
|
31507
31507
|
},
|
|
31508
31508
|
true
|
|
31509
31509
|
);
|
|
@@ -31517,7 +31517,7 @@ async function mutate(method, path, body, opts) {
|
|
|
31517
31517
|
action: `${method} ${path}`,
|
|
31518
31518
|
summary: opts.summary,
|
|
31519
31519
|
body: body ?? null,
|
|
31520
|
-
note: "
|
|
31520
|
+
note: "Plan validated (guards OK). NOTHING was changed. Run again with dryRun:false to apply."
|
|
31521
31521
|
},
|
|
31522
31522
|
false
|
|
31523
31523
|
);
|
|
@@ -31536,7 +31536,7 @@ async function deviceCreateFlow(args) {
|
|
|
31536
31536
|
if (bad) return guardError("Gd5", bad, { typeIdentifier: args.typeIdentifier });
|
|
31537
31537
|
return mutate("POST", "/devices", jsonBody2({ typeIdentifier: args.typeIdentifier, deviceItemName: args.deviceItemName, deviceName: args.deviceName }), {
|
|
31538
31538
|
dryRun: args.dryRun,
|
|
31539
|
-
summary: `
|
|
31539
|
+
summary: `create device "${args.deviceName ?? args.deviceItemName ?? "?"}" (${args.typeIdentifier})`
|
|
31540
31540
|
});
|
|
31541
31541
|
}
|
|
31542
31542
|
async function deviceChangeVersionFlow(args) {
|
|
@@ -31544,22 +31544,22 @@ async function deviceChangeVersionFlow(args) {
|
|
|
31544
31544
|
if (bad) return guardError("Gd5", bad, { typeIdentifier: args.typeIdentifier });
|
|
31545
31545
|
return mutate("POST", `/plcs/${seg2(args.plc)}/device/changeversion`, jsonBody2({ typeIdentifier: args.typeIdentifier, dryRun: args.dryRun }), {
|
|
31546
31546
|
dryRun: args.dryRun,
|
|
31547
|
-
summary: `
|
|
31547
|
+
summary: `change firmware of CPU "${args.plc}" to ${args.typeIdentifier}`
|
|
31548
31548
|
});
|
|
31549
31549
|
}
|
|
31550
31550
|
var dryRunField = {
|
|
31551
|
-
dryRun: external_exports.boolean().optional().describe("Gd11:
|
|
31551
|
+
dryRun: external_exports.boolean().optional().describe("Gd11: plan-without-applying \u2014 validates the guards and describes the action WITHOUT mutating the project")
|
|
31552
31552
|
};
|
|
31553
31553
|
function registerAuthoringTools(server2) {
|
|
31554
31554
|
server2.registerTool(
|
|
31555
31555
|
"tia_device_create",
|
|
31556
31556
|
{
|
|
31557
|
-
title: "TIA \u2014
|
|
31558
|
-
description: "
|
|
31557
|
+
title: "TIA \u2014 create device",
|
|
31558
|
+
description: "Creates a device (CPU/HMI/IO) by typeIdentifier. Guard Gd5: '/V<fw>' (slash), never ':V' \u2014 resolve via tia_catalog. Maps to POST /devices. Class M-off.",
|
|
31559
31559
|
inputSchema: {
|
|
31560
|
-
typeIdentifier: external_exports.string().describe("OrderNumber:<MLFB>/V<fw> (Gd5;
|
|
31561
|
-
deviceItemName: external_exports.string().optional().describe("
|
|
31562
|
-
deviceName: external_exports.string().optional().describe("
|
|
31560
|
+
typeIdentifier: external_exports.string().describe("OrderNumber:<MLFB>/V<fw> (Gd5; resolve via tia_catalog)"),
|
|
31561
|
+
deviceItemName: external_exports.string().optional().describe("device item name (e.g., the module/CPU)"),
|
|
31562
|
+
deviceName: external_exports.string().optional().describe("device name (station)"),
|
|
31563
31563
|
...dryRunField
|
|
31564
31564
|
}
|
|
31565
31565
|
},
|
|
@@ -31568,11 +31568,11 @@ function registerAuthoringTools(server2) {
|
|
|
31568
31568
|
server2.registerTool(
|
|
31569
31569
|
"tia_device_change_version",
|
|
31570
31570
|
{
|
|
31571
|
-
title: "TIA \u2014
|
|
31572
|
-
description: "
|
|
31571
|
+
title: "TIA \u2014 change CPU firmware (in-place)",
|
|
31572
|
+
description: "Changes the CPU's FIRMWARE version IN-PLACE (wraps DeviceItem.ChangeType), PRESERVING the program \u2014 an alternative to delete+recreate (enables 'auto-FW-match'). Guard Gd5: the typeIdentifier follows 'OrderNumber:<MLFB>/V<fw>' with '/V' (slash), never ':V' \u2014 resolve via tia_catalog. Rule: the PROJECT's firmware version must be \u2264 the physical DEVICE's (project FW \u2264 device FW). dryRun (Gd11) returns the plan without mutating. Maps to POST /plcs/{plc}/device/changeversion. Class M-off.",
|
|
31573
31573
|
inputSchema: {
|
|
31574
|
-
plc: external_exports.string().describe("
|
|
31575
|
-
typeIdentifier: external_exports.string().describe('OrderNumber:<MLFB>/V<fw>
|
|
31574
|
+
plc: external_exports.string().describe("name of the PLC (CPU) whose firmware will be changed"),
|
|
31575
|
+
typeIdentifier: external_exports.string().describe('OrderNumber:<MLFB>/V<fw> of the target firmware (Gd5; resolve via tia_catalog) \u2014 e.g.: "OrderNumber:6ES7 214-1HG40-0XB0/V4.4"'),
|
|
31576
31576
|
...dryRunField
|
|
31577
31577
|
}
|
|
31578
31578
|
},
|
|
@@ -31581,14 +31581,14 @@ function registerAuthoringTools(server2) {
|
|
|
31581
31581
|
server2.registerTool(
|
|
31582
31582
|
"tia_device_plug",
|
|
31583
31583
|
{
|
|
31584
|
-
title: "TIA \u2014
|
|
31585
|
-
description: "
|
|
31584
|
+
title: "TIA \u2014 plug module",
|
|
31585
|
+
description: "Plugs a module into an existing device by typeIdentifier (Gd5: '/V', never ':V'; resolve via tia_catalog). Maps to POST /devices/{device}/plug. M-off.",
|
|
31586
31586
|
inputSchema: {
|
|
31587
|
-
device: external_exports.string().describe("
|
|
31588
|
-
typeIdentifier: external_exports.string().describe("OrderNumber:<MLFB>/V<fw>
|
|
31589
|
-
name: external_exports.string().optional().describe("
|
|
31590
|
-
position: external_exports.number().int().optional().describe("slot/
|
|
31591
|
-
host: external_exports.string().optional().describe("device item host (rack/rail),
|
|
31587
|
+
device: external_exports.string().describe("target device name"),
|
|
31588
|
+
typeIdentifier: external_exports.string().describe("OrderNumber:<MLFB>/V<fw> of the module (Gd5)"),
|
|
31589
|
+
name: external_exports.string().optional().describe("name of the plugged module"),
|
|
31590
|
+
position: external_exports.number().int().optional().describe("slot/position (default: next free)"),
|
|
31591
|
+
host: external_exports.string().optional().describe("device item host (rack/rail), if applicable"),
|
|
31592
31592
|
...dryRunField
|
|
31593
31593
|
}
|
|
31594
31594
|
},
|
|
@@ -31597,367 +31597,367 @@ function registerAuthoringTools(server2) {
|
|
|
31597
31597
|
if (bad) return guardError("Gd5", bad, { typeIdentifier });
|
|
31598
31598
|
return mutate("POST", `/devices/${seg2(device)}/plug`, jsonBody2({ typeIdentifier, name, position, host }), {
|
|
31599
31599
|
dryRun,
|
|
31600
|
-
summary: `
|
|
31600
|
+
summary: `plug "${name ?? typeIdentifier}" into ${device}`
|
|
31601
31601
|
});
|
|
31602
31602
|
}
|
|
31603
31603
|
);
|
|
31604
31604
|
server2.registerTool(
|
|
31605
31605
|
"tia_device_unplug",
|
|
31606
31606
|
{
|
|
31607
|
-
title: "TIA \u2014
|
|
31608
|
-
description: "
|
|
31607
|
+
title: "TIA \u2014 unplug module",
|
|
31608
|
+
description: "Removes a device item (module). Maps to DELETE /devices/{device}/items/{item}. M-off.",
|
|
31609
31609
|
inputSchema: {
|
|
31610
|
-
device: external_exports.string().describe("
|
|
31611
|
-
item: external_exports.string().describe("
|
|
31610
|
+
device: external_exports.string().describe("device name"),
|
|
31611
|
+
item: external_exports.string().describe("name of the device item to remove"),
|
|
31612
31612
|
...dryRunField
|
|
31613
31613
|
}
|
|
31614
31614
|
},
|
|
31615
|
-
async ({ device, item, dryRun }) => mutate("DELETE", `/devices/${seg2(device)}/items/${seg2(item)}`, void 0, { dryRun, summary: `
|
|
31615
|
+
async ({ device, item, dryRun }) => mutate("DELETE", `/devices/${seg2(device)}/items/${seg2(item)}`, void 0, { dryRun, summary: `unplug ${item} from ${device}` })
|
|
31616
31616
|
);
|
|
31617
31617
|
server2.registerTool(
|
|
31618
31618
|
"tia_device_group_create",
|
|
31619
31619
|
{
|
|
31620
|
-
title: "TIA \u2014
|
|
31621
|
-
description: "
|
|
31622
|
-
inputSchema: { name: external_exports.string().describe("
|
|
31620
|
+
title: "TIA \u2014 create device group",
|
|
31621
|
+
description: "Creates a device group. Maps to POST /devicegroups. M-off.",
|
|
31622
|
+
inputSchema: { name: external_exports.string().describe("group name"), ...dryRunField }
|
|
31623
31623
|
},
|
|
31624
|
-
async ({ name, dryRun }) => mutate("POST", "/devicegroups", jsonBody2({ name }), { dryRun, summary: `
|
|
31624
|
+
async ({ name, dryRun }) => mutate("POST", "/devicegroups", jsonBody2({ name }), { dryRun, summary: `create device group ${name}` })
|
|
31625
31625
|
);
|
|
31626
31626
|
server2.registerTool(
|
|
31627
31627
|
"tia_subnet_create",
|
|
31628
31628
|
{
|
|
31629
|
-
title: "TIA \u2014
|
|
31630
|
-
description: "
|
|
31629
|
+
title: "TIA \u2014 create subnet",
|
|
31630
|
+
description: "Creates a subnet by typeIdentifier (Gd5: '/V', never ':V'). Maps to POST /subnets. M-off.",
|
|
31631
31631
|
inputSchema: {
|
|
31632
|
-
typeIdentifier: external_exports.string().describe("typeIdentifier
|
|
31633
|
-
name: external_exports.string().optional().describe("
|
|
31632
|
+
typeIdentifier: external_exports.string().describe("subnet typeIdentifier (Gd5)"),
|
|
31633
|
+
name: external_exports.string().optional().describe("subnet name"),
|
|
31634
31634
|
...dryRunField
|
|
31635
31635
|
}
|
|
31636
31636
|
},
|
|
31637
31637
|
async ({ typeIdentifier, name, dryRun }) => {
|
|
31638
31638
|
const bad = gd5Violation(typeIdentifier);
|
|
31639
31639
|
if (bad) return guardError("Gd5", bad, { typeIdentifier });
|
|
31640
|
-
return mutate("POST", "/subnets", jsonBody2({ typeIdentifier, name }), { dryRun, summary: `
|
|
31640
|
+
return mutate("POST", "/subnets", jsonBody2({ typeIdentifier, name }), { dryRun, summary: `create subnet ${name ?? typeIdentifier}` });
|
|
31641
31641
|
}
|
|
31642
31642
|
);
|
|
31643
31643
|
server2.registerTool(
|
|
31644
31644
|
"tia_network_connect",
|
|
31645
31645
|
{
|
|
31646
|
-
title: "TIA \u2014
|
|
31647
|
-
description: "
|
|
31646
|
+
title: "TIA \u2014 connect to subnet",
|
|
31647
|
+
description: "Connects a device's interface to a subnet (with IP; optionally creates an IO-system). CPU and IO-devices MUST be on the SAME subnet. Maps to POST /network/connect. M-off.",
|
|
31648
31648
|
inputSchema: {
|
|
31649
|
-
device: external_exports.string().describe("
|
|
31650
|
-
subnet: external_exports.string().describe("
|
|
31651
|
-
ip: external_exports.string().optional().describe("
|
|
31652
|
-
createIoSystem: external_exports.boolean().optional().describe("
|
|
31653
|
-
ioSystemName: external_exports.string().optional().describe("
|
|
31649
|
+
device: external_exports.string().describe("device name"),
|
|
31650
|
+
subnet: external_exports.string().describe("subnet name"),
|
|
31651
|
+
ip: external_exports.string().optional().describe("IP address (e.g., 192.168.0.1)"),
|
|
31652
|
+
createIoSystem: external_exports.boolean().optional().describe("create an IO-system on this connection"),
|
|
31653
|
+
ioSystemName: external_exports.string().optional().describe("IO-system name (if createIoSystem)"),
|
|
31654
31654
|
...dryRunField
|
|
31655
31655
|
}
|
|
31656
31656
|
},
|
|
31657
31657
|
async ({ device, subnet, ip, createIoSystem, ioSystemName, dryRun }) => mutate("POST", "/network/connect", jsonBody2({ device, subnet, ip, createIoSystem, ioSystemName }), {
|
|
31658
31658
|
dryRun,
|
|
31659
|
-
summary: `
|
|
31659
|
+
summary: `connect ${device} to subnet ${subnet}${ip ? " @" + ip : ""}`
|
|
31660
31660
|
})
|
|
31661
31661
|
);
|
|
31662
31662
|
server2.registerTool(
|
|
31663
31663
|
"tia_network_address",
|
|
31664
31664
|
{
|
|
31665
|
-
title: "TIA \u2014
|
|
31666
|
-
description: "
|
|
31665
|
+
title: "TIA \u2014 set network address",
|
|
31666
|
+
description: "Sets address attributes (IP/mask/etc.) of a device's interface. Maps to POST /network/address. M-off.",
|
|
31667
31667
|
inputSchema: {
|
|
31668
|
-
device: external_exports.string().describe("
|
|
31669
|
-
attributes: external_exports.record(external_exports.string(), external_exports.unknown()).describe("
|
|
31668
|
+
device: external_exports.string().describe("device name"),
|
|
31669
|
+
attributes: external_exports.record(external_exports.string(), external_exports.unknown()).describe("address attributes (e.g., { Address: '192.168.0.1' })"),
|
|
31670
31670
|
...dryRunField
|
|
31671
31671
|
}
|
|
31672
31672
|
},
|
|
31673
|
-
async ({ device, attributes, dryRun }) => mutate("POST", "/network/address", jsonBody2({ device, attributes }), { dryRun, summary: `
|
|
31673
|
+
async ({ device, attributes, dryRun }) => mutate("POST", "/network/address", jsonBody2({ device, attributes }), { dryRun, summary: `address ${device}` })
|
|
31674
31674
|
);
|
|
31675
31675
|
server2.registerTool(
|
|
31676
31676
|
"tia_network_disconnect",
|
|
31677
31677
|
{
|
|
31678
|
-
title: "TIA \u2014
|
|
31679
|
-
description: "
|
|
31680
|
-
inputSchema: { device: external_exports.string().describe("
|
|
31678
|
+
title: "TIA \u2014 disconnect from subnet",
|
|
31679
|
+
description: "Disconnects a device's interface from the subnet. Maps to POST /network/disconnect. M-off.",
|
|
31680
|
+
inputSchema: { device: external_exports.string().describe("device name"), ...dryRunField }
|
|
31681
31681
|
},
|
|
31682
|
-
async ({ device, dryRun }) => mutate("POST", "/network/disconnect", jsonBody2({ device }), { dryRun, summary: `
|
|
31682
|
+
async ({ device, dryRun }) => mutate("POST", "/network/disconnect", jsonBody2({ device }), { dryRun, summary: `disconnect ${device} from the subnet` })
|
|
31683
31683
|
);
|
|
31684
31684
|
server2.registerTool(
|
|
31685
31685
|
"tia_tagtable_create",
|
|
31686
31686
|
{
|
|
31687
|
-
title: "TIA \u2014
|
|
31688
|
-
description: "
|
|
31689
|
-
inputSchema: { plc: external_exports.string().describe("
|
|
31687
|
+
title: "TIA \u2014 create tag table",
|
|
31688
|
+
description: "Creates a tag table on a PLC. Maps to POST /plcs/{plc}/tagtables. M-off.",
|
|
31689
|
+
inputSchema: { plc: external_exports.string().describe("PLC name"), name: external_exports.string().describe("table name"), ...dryRunField }
|
|
31690
31690
|
},
|
|
31691
|
-
async ({ plc, name, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/tagtables`, jsonBody2({ name }), { dryRun, summary: `
|
|
31691
|
+
async ({ plc, name, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/tagtables`, jsonBody2({ name }), { dryRun, summary: `create tag table ${name} on ${plc}` })
|
|
31692
31692
|
);
|
|
31693
31693
|
server2.registerTool(
|
|
31694
31694
|
"tia_tag_create",
|
|
31695
31695
|
{
|
|
31696
|
-
title: "TIA \u2014
|
|
31697
|
-
description: "
|
|
31696
|
+
title: "TIA \u2014 create tag",
|
|
31697
|
+
description: "Creates a tag in a table. Maps to POST /plcs/{plc}/tags. M-off.",
|
|
31698
31698
|
inputSchema: {
|
|
31699
|
-
plc: external_exports.string().describe("
|
|
31700
|
-
table: external_exports.string().optional().describe("
|
|
31701
|
-
name: external_exports.string().describe("
|
|
31702
|
-
dataType: external_exports.string().describe("
|
|
31703
|
-
address: external_exports.string().optional().describe("
|
|
31699
|
+
plc: external_exports.string().describe("PLC name"),
|
|
31700
|
+
table: external_exports.string().optional().describe("tag table (default: the standard one)"),
|
|
31701
|
+
name: external_exports.string().describe("tag name"),
|
|
31702
|
+
dataType: external_exports.string().describe("data type (e.g., Bool, Int, Word)"),
|
|
31703
|
+
address: external_exports.string().optional().describe("address (e.g., %I0.0, %M10.0)"),
|
|
31704
31704
|
...dryRunField
|
|
31705
31705
|
}
|
|
31706
31706
|
},
|
|
31707
|
-
async ({ plc, table, name, dataType, address, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/tags`, jsonBody2({ table, name, dataType, address }), { dryRun, summary: `
|
|
31707
|
+
async ({ plc, table, name, dataType, address, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/tags`, jsonBody2({ table, name, dataType, address }), { dryRun, summary: `create tag ${name}:${dataType} on ${plc}` })
|
|
31708
31708
|
);
|
|
31709
31709
|
server2.registerTool(
|
|
31710
31710
|
"tia_tag_delete",
|
|
31711
31711
|
{
|
|
31712
|
-
title: "TIA \u2014
|
|
31713
|
-
description: "
|
|
31712
|
+
title: "TIA \u2014 delete tag",
|
|
31713
|
+
description: "Deletes a tag from a table. Maps to DELETE /plcs/{plc}/tagtables/{table}/tags/{tag}. M-off.",
|
|
31714
31714
|
inputSchema: {
|
|
31715
|
-
plc: external_exports.string().describe("
|
|
31716
|
-
table: external_exports.string().describe("
|
|
31717
|
-
tag: external_exports.string().describe("
|
|
31715
|
+
plc: external_exports.string().describe("PLC name"),
|
|
31716
|
+
table: external_exports.string().describe("tag table"),
|
|
31717
|
+
tag: external_exports.string().describe("tag name"),
|
|
31718
31718
|
...dryRunField
|
|
31719
31719
|
}
|
|
31720
31720
|
},
|
|
31721
|
-
async ({ plc, table, tag, dryRun }) => mutate("DELETE", `/plcs/${seg2(plc)}/tagtables/${seg2(table)}/tags/${seg2(tag)}`, void 0, { dryRun, summary: `
|
|
31721
|
+
async ({ plc, table, tag, dryRun }) => mutate("DELETE", `/plcs/${seg2(plc)}/tagtables/${seg2(table)}/tags/${seg2(tag)}`, void 0, { dryRun, summary: `delete tag ${tag}` })
|
|
31722
31722
|
);
|
|
31723
31723
|
server2.registerTool(
|
|
31724
31724
|
"tia_constant_create",
|
|
31725
31725
|
{
|
|
31726
|
-
title: "TIA \u2014
|
|
31727
|
-
description: "
|
|
31726
|
+
title: "TIA \u2014 create constant",
|
|
31727
|
+
description: "Creates a user constant in a tag table. Maps to POST /plcs/{plc}/constants. M-off.",
|
|
31728
31728
|
inputSchema: {
|
|
31729
|
-
plc: external_exports.string().describe("
|
|
31730
|
-
table: external_exports.string().optional().describe("
|
|
31731
|
-
name: external_exports.string().describe("
|
|
31732
|
-
dataType: external_exports.string().describe("
|
|
31733
|
-
value: external_exports.string().describe("
|
|
31729
|
+
plc: external_exports.string().describe("PLC name"),
|
|
31730
|
+
table: external_exports.string().optional().describe("tag table (default: the standard one)"),
|
|
31731
|
+
name: external_exports.string().describe("constant name"),
|
|
31732
|
+
dataType: external_exports.string().describe("data type"),
|
|
31733
|
+
value: external_exports.string().describe("value"),
|
|
31734
31734
|
...dryRunField
|
|
31735
31735
|
}
|
|
31736
31736
|
},
|
|
31737
|
-
async ({ plc, table, name, dataType, value, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/constants`, jsonBody2({ table, name, dataType, value }), { dryRun, summary: `
|
|
31737
|
+
async ({ plc, table, name, dataType, value, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/constants`, jsonBody2({ table, name, dataType, value }), { dryRun, summary: `create constant ${name} on ${plc}` })
|
|
31738
31738
|
);
|
|
31739
31739
|
server2.registerTool(
|
|
31740
31740
|
"tia_fb_create",
|
|
31741
31741
|
{
|
|
31742
|
-
title: "TIA \u2014
|
|
31743
|
-
description: "
|
|
31742
|
+
title: "TIA \u2014 create FB",
|
|
31743
|
+
description: "Creates a Function Block. Gd6: for LOGIC use a textual language (SCL) via tia_source_put, or graphical (LAD/FBD) via tia_import_xml. Maps to POST /plcs/{plc}/fbs. M-off.",
|
|
31744
31744
|
inputSchema: {
|
|
31745
|
-
plc: external_exports.string().describe("
|
|
31746
|
-
name: external_exports.string().describe("
|
|
31747
|
-
language: external_exports.string().optional().describe("
|
|
31748
|
-
autoNumber: external_exports.boolean().optional().describe("
|
|
31749
|
-
number: external_exports.number().int().optional().describe("
|
|
31750
|
-
group: external_exports.string().optional().describe("
|
|
31745
|
+
plc: external_exports.string().describe("PLC name"),
|
|
31746
|
+
name: external_exports.string().describe("FB name"),
|
|
31747
|
+
language: external_exports.string().optional().describe("language (e.g., SCL, LAD, FBD; project default)"),
|
|
31748
|
+
autoNumber: external_exports.boolean().optional().describe("automatic numbering (default true; omit 'number' for auto)"),
|
|
31749
|
+
number: external_exports.number().int().optional().describe("block number \u22651 (only with autoNumber=false); omitted or 0 \u21D2 automatic numbering"),
|
|
31750
|
+
group: external_exports.string().optional().describe("target block group"),
|
|
31751
31751
|
...dryRunField
|
|
31752
31752
|
}
|
|
31753
31753
|
},
|
|
31754
|
-
async ({ plc, name, language, autoNumber, number: number4, group, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/fbs`, jsonBody2({ name, language, autoNumber, number: number4, group }), { dryRun, summary: `
|
|
31754
|
+
async ({ plc, name, language, autoNumber, number: number4, group, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/fbs`, jsonBody2({ name, language, autoNumber, number: number4, group }), { dryRun, summary: `create FB ${name} on ${plc}` })
|
|
31755
31755
|
);
|
|
31756
31756
|
server2.registerTool(
|
|
31757
31757
|
"tia_instancedb_create",
|
|
31758
31758
|
{
|
|
31759
|
-
title: "TIA \u2014
|
|
31760
|
-
description: "
|
|
31759
|
+
title: "TIA \u2014 create instance DB",
|
|
31760
|
+
description: "Creates an instance DB of an FB. Maps to POST /plcs/{plc}/instancedbs. M-off.",
|
|
31761
31761
|
inputSchema: {
|
|
31762
|
-
plc: external_exports.string().describe("
|
|
31763
|
-
name: external_exports.string().describe("
|
|
31764
|
-
instanceOf: external_exports.string().describe("
|
|
31765
|
-
autoNumber: external_exports.boolean().optional().describe("
|
|
31766
|
-
number: external_exports.number().int().optional().describe("
|
|
31767
|
-
group: external_exports.string().optional().describe("
|
|
31762
|
+
plc: external_exports.string().describe("PLC name"),
|
|
31763
|
+
name: external_exports.string().describe("instance DB name"),
|
|
31764
|
+
instanceOf: external_exports.string().describe("name of the FB to instantiate from"),
|
|
31765
|
+
autoNumber: external_exports.boolean().optional().describe("automatic numbering (default true; omit 'number' for auto)"),
|
|
31766
|
+
number: external_exports.number().int().optional().describe("block number \u22651 (only with autoNumber=false); omitted or 0 \u21D2 automatic numbering"),
|
|
31767
|
+
group: external_exports.string().optional().describe("target block group"),
|
|
31768
31768
|
...dryRunField
|
|
31769
31769
|
}
|
|
31770
31770
|
},
|
|
31771
31771
|
async ({ plc, name, instanceOf, autoNumber, number: number4, group, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/instancedbs`, jsonBody2({ name, instanceOf, autoNumber, number: number4, group }), {
|
|
31772
31772
|
dryRun,
|
|
31773
|
-
summary: `
|
|
31773
|
+
summary: `create iDB ${name} from ${instanceOf} on ${plc}`
|
|
31774
31774
|
})
|
|
31775
31775
|
);
|
|
31776
31776
|
server2.registerTool(
|
|
31777
31777
|
"tia_block_delete",
|
|
31778
31778
|
{
|
|
31779
|
-
title: "TIA \u2014
|
|
31780
|
-
description: "
|
|
31781
|
-
inputSchema: { plc: external_exports.string().describe("
|
|
31779
|
+
title: "TIA \u2014 delete block",
|
|
31780
|
+
description: "Deletes a block. Maps to DELETE /plcs/{plc}/blocks/{block}. M-off.",
|
|
31781
|
+
inputSchema: { plc: external_exports.string().describe("PLC name"), block: external_exports.string().describe("block name"), ...dryRunField }
|
|
31782
31782
|
},
|
|
31783
|
-
async ({ plc, block, dryRun }) => mutate("DELETE", `/plcs/${seg2(plc)}/blocks/${seg2(block)}`, void 0, { dryRun, summary: `
|
|
31783
|
+
async ({ plc, block, dryRun }) => mutate("DELETE", `/plcs/${seg2(plc)}/blocks/${seg2(block)}`, void 0, { dryRun, summary: `delete block ${block}` })
|
|
31784
31784
|
);
|
|
31785
31785
|
server2.registerTool(
|
|
31786
31786
|
"tia_block_set_attribute",
|
|
31787
31787
|
{
|
|
31788
|
-
title: "TIA \u2014
|
|
31789
|
-
description: "
|
|
31788
|
+
title: "TIA \u2014 set block attribute",
|
|
31789
|
+
description: "Sets an attribute of a block (e.g., optimized access). Maps to POST /plcs/{plc}/blocks/{block}/attributes. M-off.",
|
|
31790
31790
|
inputSchema: {
|
|
31791
|
-
plc: external_exports.string().describe("
|
|
31792
|
-
block: external_exports.string().describe("
|
|
31793
|
-
name: external_exports.string().describe("
|
|
31794
|
-
value: external_exports.unknown().describe("
|
|
31791
|
+
plc: external_exports.string().describe("PLC name"),
|
|
31792
|
+
block: external_exports.string().describe("block name"),
|
|
31793
|
+
name: external_exports.string().describe("attribute name"),
|
|
31794
|
+
value: external_exports.unknown().describe("attribute value"),
|
|
31795
31795
|
...dryRunField
|
|
31796
31796
|
}
|
|
31797
31797
|
},
|
|
31798
31798
|
async ({ plc, block, name, value, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/blocks/${seg2(block)}/attributes`, jsonBody2({ name, value }), {
|
|
31799
31799
|
dryRun,
|
|
31800
|
-
summary: `set ${name}
|
|
31800
|
+
summary: `set ${name} on ${block}`
|
|
31801
31801
|
})
|
|
31802
31802
|
);
|
|
31803
31803
|
server2.registerTool(
|
|
31804
31804
|
"tia_block_group_create",
|
|
31805
31805
|
{
|
|
31806
|
-
title: "TIA \u2014
|
|
31807
|
-
description: "
|
|
31808
|
-
inputSchema: { plc: external_exports.string().describe("
|
|
31806
|
+
title: "TIA \u2014 create block group",
|
|
31807
|
+
description: "Creates a block group. Maps to POST /plcs/{plc}/blockgroups. M-off.",
|
|
31808
|
+
inputSchema: { plc: external_exports.string().describe("PLC name"), name: external_exports.string().describe("group name"), ...dryRunField }
|
|
31809
31809
|
},
|
|
31810
|
-
async ({ plc, name, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/blockgroups`, jsonBody2({ name }), { dryRun, summary: `
|
|
31810
|
+
async ({ plc, name, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/blockgroups`, jsonBody2({ name }), { dryRun, summary: `create block group ${name}` })
|
|
31811
31811
|
);
|
|
31812
31812
|
server2.registerTool(
|
|
31813
31813
|
"tia_type_group_create",
|
|
31814
31814
|
{
|
|
31815
|
-
title: "TIA \u2014
|
|
31816
|
-
description: "
|
|
31817
|
-
inputSchema: { plc: external_exports.string().describe("
|
|
31815
|
+
title: "TIA \u2014 create type group",
|
|
31816
|
+
description: "Creates a type group (UDTs). Maps to POST /plcs/{plc}/typegroups. M-off.",
|
|
31817
|
+
inputSchema: { plc: external_exports.string().describe("PLC name"), name: external_exports.string().describe("group name"), ...dryRunField }
|
|
31818
31818
|
},
|
|
31819
|
-
async ({ plc, name, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/typegroups`, jsonBody2({ name }), { dryRun, summary: `
|
|
31819
|
+
async ({ plc, name, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/typegroups`, jsonBody2({ name }), { dryRun, summary: `create type group ${name}` })
|
|
31820
31820
|
);
|
|
31821
31821
|
server2.registerTool(
|
|
31822
31822
|
"tia_type_delete",
|
|
31823
31823
|
{
|
|
31824
|
-
title: "TIA \u2014
|
|
31825
|
-
description: "
|
|
31826
|
-
inputSchema: { plc: external_exports.string().describe("
|
|
31824
|
+
title: "TIA \u2014 delete type",
|
|
31825
|
+
description: "Deletes a type (UDT). Maps to DELETE /plcs/{plc}/types/{type}. M-off.",
|
|
31826
|
+
inputSchema: { plc: external_exports.string().describe("PLC name"), type: external_exports.string().describe("type name"), ...dryRunField }
|
|
31827
31827
|
},
|
|
31828
|
-
async ({ plc, type, dryRun }) => mutate("DELETE", `/plcs/${seg2(plc)}/types/${seg2(type)}`, void 0, { dryRun, summary: `
|
|
31828
|
+
async ({ plc, type, dryRun }) => mutate("DELETE", `/plcs/${seg2(plc)}/types/${seg2(type)}`, void 0, { dryRun, summary: `delete type ${type}` })
|
|
31829
31829
|
);
|
|
31830
31830
|
server2.registerTool(
|
|
31831
31831
|
"tia_source_put",
|
|
31832
31832
|
{
|
|
31833
|
-
title: "TIA \u2014
|
|
31834
|
-
description: "
|
|
31833
|
+
title: "TIA \u2014 write/compile SCL source",
|
|
31834
|
+
description: "Writes a block from textual SCL source and (optionally) compiles it. Gd6: use THIS for TEXTUAL language (SCL/STL); for graphical (LAD/FBD/GRAPH) use tia_import_xml. Maps to POST /plcs/{plc}/source. M-off.",
|
|
31835
31835
|
inputSchema: {
|
|
31836
|
-
plc: external_exports.string().describe("
|
|
31837
|
-
name: external_exports.string().describe("
|
|
31838
|
-
code: external_exports.string().describe("
|
|
31839
|
-
compile: external_exports.boolean().optional().describe("
|
|
31836
|
+
plc: external_exports.string().describe("PLC name"),
|
|
31837
|
+
name: external_exports.string().describe("block/source name"),
|
|
31838
|
+
code: external_exports.string().describe("SCL source code"),
|
|
31839
|
+
compile: external_exports.boolean().optional().describe("compile after generating (default false)"),
|
|
31840
31840
|
...dryRunField
|
|
31841
31841
|
}
|
|
31842
31842
|
},
|
|
31843
|
-
async ({ plc, name, code, compile, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/source`, jsonBody2({ name, code, compile }), { dryRun, summary: `
|
|
31843
|
+
async ({ plc, name, code, compile, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/source`, jsonBody2({ name, code, compile }), { dryRun, summary: `write SCL ${name} on ${plc}` })
|
|
31844
31844
|
);
|
|
31845
31845
|
server2.registerTool(
|
|
31846
31846
|
"tia_import_xml",
|
|
31847
31847
|
{
|
|
31848
|
-
title: "TIA \u2014
|
|
31849
|
-
description: "
|
|
31848
|
+
title: "TIA \u2014 import block (SimaticML XML)",
|
|
31849
|
+
description: "Imports a block in SimaticML XML (the only path for LAD/FBD/GRAPH \u2014 Gd6). Gd7: the SimaticML version must match V21. Import UDTs FIRST (tia_types_import). Accepts `xml` in the body or `path` on the host. Maps to POST /plcs/{plc}/import. M-off.",
|
|
31850
31850
|
inputSchema: {
|
|
31851
|
-
plc: external_exports.string().describe("
|
|
31852
|
-
xml: external_exports.string().optional().describe("
|
|
31853
|
-
path: external_exports.string().optional().describe("
|
|
31854
|
-
override: external_exports.boolean().optional().describe("
|
|
31851
|
+
plc: external_exports.string().describe("PLC name"),
|
|
31852
|
+
xml: external_exports.string().optional().describe("SimaticML XML content (alternative to path)"),
|
|
31853
|
+
path: external_exports.string().optional().describe("path to the .xml on the serve host (alternative to xml)"),
|
|
31854
|
+
override: external_exports.boolean().optional().describe("overwrite if it already exists (default true)"),
|
|
31855
31855
|
...dryRunField
|
|
31856
31856
|
}
|
|
31857
31857
|
},
|
|
31858
|
-
async ({ plc, xml, path, override, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/import`, jsonBody2({ xml, path, override }), { dryRun, summary: `
|
|
31858
|
+
async ({ plc, xml, path, override, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/import`, jsonBody2({ xml, path, override }), { dryRun, summary: `import XML on ${plc}` })
|
|
31859
31859
|
);
|
|
31860
31860
|
server2.registerTool(
|
|
31861
31861
|
"tia_types_import",
|
|
31862
31862
|
{
|
|
31863
|
-
title: "TIA \u2014
|
|
31864
|
-
description: "
|
|
31863
|
+
title: "TIA \u2014 import type/UDT (SimaticML XML)",
|
|
31864
|
+
description: "Imports a UDT in SimaticML XML. Import UDTs BEFORE the blocks that use them (Gd6). Maps to POST /plcs/{plc}/types/import. M-off.",
|
|
31865
31865
|
inputSchema: {
|
|
31866
|
-
plc: external_exports.string().describe("
|
|
31867
|
-
xml: external_exports.string().optional().describe("
|
|
31868
|
-
path: external_exports.string().optional().describe("
|
|
31869
|
-
override: external_exports.boolean().optional().describe("
|
|
31866
|
+
plc: external_exports.string().describe("PLC name"),
|
|
31867
|
+
xml: external_exports.string().optional().describe("SimaticML XML content of the UDT (alternative to path)"),
|
|
31868
|
+
path: external_exports.string().optional().describe("path to the .xml on the host (alternative to xml)"),
|
|
31869
|
+
override: external_exports.boolean().optional().describe("overwrite if it already exists (default true)"),
|
|
31870
31870
|
...dryRunField
|
|
31871
31871
|
}
|
|
31872
31872
|
},
|
|
31873
|
-
async ({ plc, xml, path, override, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/types/import`, jsonBody2({ xml, path, override }), { dryRun, summary: `
|
|
31873
|
+
async ({ plc, xml, path, override, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/types/import`, jsonBody2({ xml, path, override }), { dryRun, summary: `import UDT on ${plc}` })
|
|
31874
31874
|
);
|
|
31875
31875
|
server2.registerTool(
|
|
31876
31876
|
"tia_export_xml",
|
|
31877
31877
|
{
|
|
31878
|
-
title: "TIA \u2014
|
|
31879
|
-
description: "
|
|
31878
|
+
title: "TIA \u2014 export blocks/types (SimaticML XML)",
|
|
31879
|
+
description: "Exports the PLC's blocks and types to SimaticML XML files in a directory (project-as-code). Maps to POST /plcs/{plc}/export. M-off.",
|
|
31880
31880
|
inputSchema: {
|
|
31881
|
-
plc: external_exports.string().describe("
|
|
31882
|
-
directory: external_exports.string().describe("
|
|
31881
|
+
plc: external_exports.string().describe("PLC name"),
|
|
31882
|
+
directory: external_exports.string().describe("target directory on the serve host"),
|
|
31883
31883
|
...dryRunField
|
|
31884
31884
|
}
|
|
31885
31885
|
},
|
|
31886
|
-
async ({ plc, directory, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/export`, jsonBody2({ directory }), { dryRun, summary: `
|
|
31886
|
+
async ({ plc, directory, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/export`, jsonBody2({ directory }), { dryRun, summary: `export XML from ${plc} to ${directory}` })
|
|
31887
31887
|
);
|
|
31888
31888
|
server2.registerTool(
|
|
31889
31889
|
"tia_watchtable_create",
|
|
31890
31890
|
{
|
|
31891
|
-
title: "TIA \u2014
|
|
31892
|
-
description: "
|
|
31893
|
-
inputSchema: { plc: external_exports.string().describe("
|
|
31891
|
+
title: "TIA \u2014 create watch table",
|
|
31892
|
+
description: "Creates a watch table. Maps to POST /plcs/{plc}/watchtables. M-off.",
|
|
31893
|
+
inputSchema: { plc: external_exports.string().describe("PLC name"), name: external_exports.string().describe("watch table name"), ...dryRunField }
|
|
31894
31894
|
},
|
|
31895
|
-
async ({ plc, name, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/watchtables`, jsonBody2({ name }), { dryRun, summary: `
|
|
31895
|
+
async ({ plc, name, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/watchtables`, jsonBody2({ name }), { dryRun, summary: `create watch table ${name}` })
|
|
31896
31896
|
);
|
|
31897
31897
|
server2.registerTool(
|
|
31898
31898
|
"tia_watchtable_delete",
|
|
31899
31899
|
{
|
|
31900
|
-
title: "TIA \u2014
|
|
31901
|
-
description: "
|
|
31902
|
-
inputSchema: { plc: external_exports.string().describe("
|
|
31900
|
+
title: "TIA \u2014 delete watch table",
|
|
31901
|
+
description: "Deletes a watch table. Maps to DELETE /plcs/{plc}/watchtables/{wt}. M-off.",
|
|
31902
|
+
inputSchema: { plc: external_exports.string().describe("PLC name"), watchtable: external_exports.string().describe("watch table name"), ...dryRunField }
|
|
31903
31903
|
},
|
|
31904
|
-
async ({ plc, watchtable, dryRun }) => mutate("DELETE", `/plcs/${seg2(plc)}/watchtables/${seg2(watchtable)}`, void 0, { dryRun, summary: `
|
|
31904
|
+
async ({ plc, watchtable, dryRun }) => mutate("DELETE", `/plcs/${seg2(plc)}/watchtables/${seg2(watchtable)}`, void 0, { dryRun, summary: `delete watch table ${watchtable}` })
|
|
31905
31905
|
);
|
|
31906
31906
|
server2.registerTool(
|
|
31907
31907
|
"tia_obj_service",
|
|
31908
31908
|
{
|
|
31909
|
-
title: "TIA \u2014
|
|
31910
|
-
description: "
|
|
31909
|
+
title: "TIA \u2014 acquire service (GetService\u2192handle)",
|
|
31910
|
+
description: "Acquires a service from an object by handle (generic GetService<T>) and returns a service HANDLE, to then invoke methods via tia_obj_invoke. E.g.: PlcMasterSecretConfigurator.Protect \u2014 unlocks a bare CPU (offline confidential-data password; generates the certificate). The acquisition itself does NOT mutate the project. Maps to POST /obj/{handle}/service {type}. M-off.",
|
|
31911
31911
|
inputSchema: {
|
|
31912
|
-
handle: external_exports.string().describe("handle
|
|
31913
|
-
type: external_exports.string().describe("
|
|
31912
|
+
handle: external_exports.string().describe("object handle (e.g., the CPU's device item)"),
|
|
31913
|
+
type: external_exports.string().describe("service type name (e.g., Siemens.Engineering.HW.Features.PlcMasterSecretConfigurator)")
|
|
31914
31914
|
}
|
|
31915
31915
|
},
|
|
31916
|
-
async ({ handle, type }) => mutate("POST", `/obj/${seg2(handle)}/service`, jsonBody2({ type }), { summary: `
|
|
31916
|
+
async ({ handle, type }) => mutate("POST", `/obj/${seg2(handle)}/service`, jsonBody2({ type }), { summary: `acquire service ${type} from obj ${handle}` })
|
|
31917
31917
|
);
|
|
31918
31918
|
server2.registerTool(
|
|
31919
31919
|
"tia_obj_set_attributes",
|
|
31920
31920
|
{
|
|
31921
|
-
title: "TIA \u2014 set
|
|
31922
|
-
description: "
|
|
31921
|
+
title: "TIA \u2014 set attributes (generic)",
|
|
31922
|
+
description: "Sets attributes of any model object by handle. Maps to POST /obj/{handle}/attributes. M-off. Use the handles from the read-only obj tools (M1).",
|
|
31923
31923
|
inputSchema: {
|
|
31924
|
-
handle: external_exports.string().describe("handle
|
|
31925
|
-
attributes: external_exports.record(external_exports.string(), external_exports.unknown()).describe("
|
|
31924
|
+
handle: external_exports.string().describe("object handle (from the read-only tia_obj_* tools)"),
|
|
31925
|
+
attributes: external_exports.record(external_exports.string(), external_exports.unknown()).describe("name\u2192value map of attributes to set"),
|
|
31926
31926
|
...dryRunField
|
|
31927
31927
|
}
|
|
31928
31928
|
},
|
|
31929
|
-
async ({ handle, attributes, dryRun }) => mutate("POST", `/obj/${seg2(handle)}/attributes`, jsonBody2({ ...attributes }), { dryRun, summary: `set
|
|
31929
|
+
async ({ handle, attributes, dryRun }) => mutate("POST", `/obj/${seg2(handle)}/attributes`, jsonBody2({ ...attributes }), { dryRun, summary: `set attributes on obj ${handle}` })
|
|
31930
31930
|
);
|
|
31931
31931
|
server2.registerTool(
|
|
31932
31932
|
"tia_obj_invoke",
|
|
31933
31933
|
{
|
|
31934
|
-
title: "TIA \u2014
|
|
31935
|
-
description: '
|
|
31934
|
+
title: "TIA \u2014 invoke method (generic)",
|
|
31935
|
+
description: 'Invokes a method of a model object by handle (args coerced to the parameter types; {"$handle":N} passes another object). Maps to POST /obj/{handle}/invoke. M-off. Powerful \u2014 combine with tia_obj_info to see the signature.',
|
|
31936
31936
|
inputSchema: {
|
|
31937
|
-
handle: external_exports.string().describe("handle
|
|
31938
|
-
name: external_exports.string().describe("
|
|
31939
|
-
args: external_exports.array(external_exports.unknown()).optional().describe("
|
|
31937
|
+
handle: external_exports.string().describe("object handle"),
|
|
31938
|
+
name: external_exports.string().describe("name of the method to invoke"),
|
|
31939
|
+
args: external_exports.array(external_exports.unknown()).optional().describe("positional arguments (coerced to the parameter types)"),
|
|
31940
31940
|
...dryRunField
|
|
31941
31941
|
}
|
|
31942
31942
|
},
|
|
31943
|
-
async ({ handle, name, args, dryRun }) => mutate("POST", `/obj/${seg2(handle)}/invoke`, jsonBody2({ name, args }), { dryRun, summary: `invoke ${name}()
|
|
31943
|
+
async ({ handle, name, args, dryRun }) => mutate("POST", `/obj/${seg2(handle)}/invoke`, jsonBody2({ name, args }), { dryRun, summary: `invoke ${name}() on obj ${handle}` })
|
|
31944
31944
|
);
|
|
31945
31945
|
server2.registerTool(
|
|
31946
31946
|
"tia_obj_create",
|
|
31947
31947
|
{
|
|
31948
|
-
title: "TIA \u2014
|
|
31949
|
-
description: "
|
|
31948
|
+
title: "TIA \u2014 create object (generic)",
|
|
31949
|
+
description: "Creates an object in a composition of a parent object by handle. Maps to POST /obj/{handle}/create. M-off. See the creatable types in tia_obj_creationinfos.",
|
|
31950
31950
|
inputSchema: {
|
|
31951
|
-
handle: external_exports.string().describe("
|
|
31952
|
-
composition: external_exports.string().describe("
|
|
31953
|
-
type: external_exports.string().describe("
|
|
31954
|
-
parameters: external_exports.record(external_exports.string(), external_exports.unknown()).optional().describe("
|
|
31951
|
+
handle: external_exports.string().describe("parent object handle"),
|
|
31952
|
+
composition: external_exports.string().describe("composition name (e.g., 'Blocks')"),
|
|
31953
|
+
type: external_exports.string().describe("type to create (Siemens type)"),
|
|
31954
|
+
parameters: external_exports.record(external_exports.string(), external_exports.unknown()).optional().describe("constructor parameters (name\u2192value)"),
|
|
31955
31955
|
...dryRunField
|
|
31956
31956
|
}
|
|
31957
31957
|
},
|
|
31958
31958
|
async ({ handle, composition, type, parameters, dryRun }) => mutate("POST", `/obj/${seg2(handle)}/create`, jsonBody2({ composition, type, parameters }), {
|
|
31959
31959
|
dryRun,
|
|
31960
|
-
summary: `
|
|
31960
|
+
summary: `create ${type} in ${composition} of obj ${handle}`
|
|
31961
31961
|
})
|
|
31962
31962
|
);
|
|
31963
31963
|
}
|
|
@@ -31995,18 +31995,18 @@ function planHash(plan) {
|
|
|
31995
31995
|
return (h >>> 0).toString(16).padStart(8, "0");
|
|
31996
31996
|
}
|
|
31997
31997
|
var GATE_INSTRUCTION = {
|
|
31998
|
-
download_approval: "
|
|
31999
|
-
go_online: "
|
|
32000
|
-
net_scan: "
|
|
31998
|
+
download_approval: "A human must APPROVE the download: it STOPS the physical CPU (StopAll), OVERWRITES system data, and RESTARTS the CPU. Review the 'plan'. WARNING: the current serve AUTO-CONFIRMS these dialogs (C# backlog P0.5) \u2014 the approval here is the safeguard at the MCP layer.",
|
|
31999
|
+
go_online: "Going ONLINE connects to the PHYSICAL PLC over the network. Confirm with a human that it is safe to connect to the target machine.",
|
|
32000
|
+
net_scan: "A network scan (accessible devices) probes the local network via the PG/PC adapter. Confirm before scanning."
|
|
32001
32001
|
};
|
|
32002
32002
|
function gateHandoff(gate, ctx) {
|
|
32003
|
-
const resume = gate === "download_approval" ? ["1.
|
|
32003
|
+
const resume = gate === "download_approval" ? ["1. Review the 'plan' (CPU, interface, options).", "2. Confirm with the line's responsible person.", `3. Re-call with approved:true and planHash:"${ctx.planHash}".`] : ["1. Confirm with a human that it's safe.", "2. Re-call the same tool with confirm:true."];
|
|
32004
32004
|
return textResult(
|
|
32005
32005
|
{
|
|
32006
32006
|
status: "requires_human_action",
|
|
32007
32007
|
gate,
|
|
32008
|
-
canDo: ctx.plc ? `${gate}
|
|
32009
|
-
youMustDo: GATE_INSTRUCTION[gate] ?? "
|
|
32008
|
+
canDo: ctx.plc ? `${gate} on ${ctx.plc}` : gate,
|
|
32009
|
+
youMustDo: GATE_INSTRUCTION[gate] ?? "Human confirmation required.",
|
|
32010
32010
|
plan: ctx.plan ?? null,
|
|
32011
32011
|
planHash: ctx.planHash ?? null,
|
|
32012
32012
|
nextSteps: resume
|
|
@@ -32020,7 +32020,7 @@ async function compileFlow(plc) {
|
|
|
32020
32020
|
const d = data ?? {};
|
|
32021
32021
|
const errors = typeof d.errors === "number" ? d.errors : null;
|
|
32022
32022
|
const clean = errors !== null ? errors === 0 : d.state === "Success";
|
|
32023
|
-
const nextHints = clean ? ["Compile
|
|
32023
|
+
const nextHints = clean ? ["Compile CLEAN (Gd8: warnings don't block). Ready for gated download (tia_download) or S7 connection."] : [`Compile with ${errors ?? "?"} ERROR(s) \u2014 fix BEFORE download/S7 (Gd9 forbids a non-clean deploy). See 'messages' (tree).`];
|
|
32024
32024
|
return textResult({ ...d, verification: { compiled: clean ? "clean" : "error", errors, warnings: d.warnings ?? null }, nextHints });
|
|
32025
32025
|
} catch (e) {
|
|
32026
32026
|
return errorResult3(asTiaError(e));
|
|
@@ -32045,16 +32045,16 @@ async function downloadFlow(args) {
|
|
|
32045
32045
|
gate: "download_approval",
|
|
32046
32046
|
plan,
|
|
32047
32047
|
planHash: hash2,
|
|
32048
|
-
gd9: "
|
|
32048
|
+
gd9: "PRECONDITION Gd9/Gd10: the project MUST be compile-clean and consistent. Run tia_compile and only proceed with errors=0.",
|
|
32049
32049
|
loadPreview: {
|
|
32050
32050
|
willConfirm: [
|
|
32051
|
-
"StopModules = StopAll \u2014
|
|
32052
|
-
"OverwriteSystemData = Overwrite \u2014
|
|
32053
|
-
"StartModules = StartModule \u2014
|
|
32051
|
+
"StopModules = StopAll \u2014 STOPS the physical CPU",
|
|
32052
|
+
"OverwriteSystemData = Overwrite \u2014 overwrites system data",
|
|
32053
|
+
"StartModules = StartModule \u2014 RESTARTS the CPU at the end"
|
|
32054
32054
|
],
|
|
32055
|
-
note: "
|
|
32055
|
+
note: "Openness has no preview-without-downloading; these are the default selections of serve's delegates. After a real download, the result carries 'configurations' with what was actually confirmed (audit trail \u2014 P0.5)."
|
|
32056
32056
|
},
|
|
32057
|
-
note: "
|
|
32057
|
+
note: "Plan validated. NOTHING was downloaded. To apply: tia_download with approved:true and this planHash (after human approval)."
|
|
32058
32058
|
},
|
|
32059
32059
|
false
|
|
32060
32060
|
);
|
|
@@ -32086,20 +32086,20 @@ function registerVerificationTools(server2) {
|
|
|
32086
32086
|
server2.registerTool(
|
|
32087
32087
|
"tia_compile",
|
|
32088
32088
|
{
|
|
32089
|
-
title: "TIA \u2014
|
|
32090
|
-
description: "
|
|
32091
|
-
inputSchema: { plc: external_exports.string().describe("
|
|
32089
|
+
title: "TIA \u2014 compile (verifier)",
|
|
32090
|
+
description: "Compiles the PLC and returns the message tree + a verification summary (Gd8: only ERROR blocks, warnings don't) and nextHints. This is the offline VERIFIER: a clean compile is a precondition (Gd9) for download/S7. Maps to POST /plcs/{plc}/compile. M-off.",
|
|
32091
|
+
inputSchema: { plc: external_exports.string().describe("PLC name") }
|
|
32092
32092
|
},
|
|
32093
32093
|
async ({ plc }) => compileFlow(plc)
|
|
32094
32094
|
);
|
|
32095
32095
|
server2.registerTool(
|
|
32096
32096
|
"tia_connection_create",
|
|
32097
32097
|
{
|
|
32098
|
-
title: "TIA \u2014
|
|
32099
|
-
description: "
|
|
32098
|
+
title: "TIA \u2014 create S7 connection",
|
|
32099
|
+
description: "Creates an S7 connection between two devices. Guard G2: requires \u22652 CONSISTENT CPUs (compile clean) \u2014 a bare CPU fails. On error, the envelope's 'details' carries the diagnostic (or use tia_connections_diagnose). Maps to POST /connections. M-off.",
|
|
32100
32100
|
inputSchema: {
|
|
32101
|
-
localDevice: external_exports.string().describe("device
|
|
32102
|
-
partnerDevice: external_exports.string().describe("device
|
|
32101
|
+
localDevice: external_exports.string().describe("local device"),
|
|
32102
|
+
partnerDevice: external_exports.string().describe("partner device")
|
|
32103
32103
|
}
|
|
32104
32104
|
},
|
|
32105
32105
|
async ({ localDevice, partnerDevice }) => send("POST", "/connections", jsonBody3({ localDevice, partnerDevice }))
|
|
@@ -32107,19 +32107,19 @@ function registerVerificationTools(server2) {
|
|
|
32107
32107
|
server2.registerTool(
|
|
32108
32108
|
"tia_download",
|
|
32109
32109
|
{
|
|
32110
|
-
title: "TIA \u2014
|
|
32111
|
-
description: "
|
|
32110
|
+
title: "TIA \u2014 download to the PLC (GATE G3)",
|
|
32111
|
+
description: "Downloads hardware/software to the PHYSICAL CPU (STOPS and RESTARTS the CPU). GATE G3: does NOT download without human approval. Use dryRun:true to get the plan + planHash (without downloading); then, after a human approves, call with approved:true and the SAME planHash. Precondition Gd9: clean compile (run tia_compile). Discover connectionMode/pcInterfaceName/targetInterfaceName via tia_accessible_devices. Maps to POST /plcs/{plc}/download.",
|
|
32112
32112
|
inputSchema: {
|
|
32113
|
-
plc: external_exports.string().describe("
|
|
32114
|
-
connectionMode: external_exports.string().optional().describe(
|
|
32115
|
-
pcInterfaceName: external_exports.string().optional().describe("
|
|
32116
|
-
pcInterfaceNumber: external_exports.number().int().optional().describe("
|
|
32117
|
-
targetInterfaceName: external_exports.string().optional().describe('
|
|
32118
|
-
hardware: external_exports.boolean().optional().describe("
|
|
32119
|
-
software: external_exports.boolean().optional().describe("
|
|
32120
|
-
dryRun: external_exports.boolean().optional().describe("Gd11:
|
|
32121
|
-
approved: external_exports.boolean().optional().describe("G3:
|
|
32122
|
-
planHash: external_exports.string().optional().describe("G3:
|
|
32113
|
+
plc: external_exports.string().describe("PLC name"),
|
|
32114
|
+
connectionMode: external_exports.string().optional().describe(`connection mode (e.g., "PN/IE") \u2014 TIA's LOCALIZED name`),
|
|
32115
|
+
pcInterfaceName: external_exports.string().optional().describe("PG/PC adapter (localized name)"),
|
|
32116
|
+
pcInterfaceNumber: external_exports.number().int().optional().describe("adapter number (default 1)"),
|
|
32117
|
+
targetInterfaceName: external_exports.string().optional().describe('target CPU interface (e.g., "1 X1")'),
|
|
32118
|
+
hardware: external_exports.boolean().optional().describe("download hardware (default false)"),
|
|
32119
|
+
software: external_exports.boolean().optional().describe("download software (default true)"),
|
|
32120
|
+
dryRun: external_exports.boolean().optional().describe("Gd11: returns the plan + planHash WITHOUT downloading"),
|
|
32121
|
+
approved: external_exports.boolean().optional().describe("G3: only true after explicit HUMAN APPROVAL"),
|
|
32122
|
+
planHash: external_exports.string().optional().describe("G3: the exact planHash returned by dryRun (binds the approval to the plan)")
|
|
32123
32123
|
}
|
|
32124
32124
|
},
|
|
32125
32125
|
async (args) => downloadFlow(args)
|
|
@@ -32127,15 +32127,15 @@ function registerVerificationTools(server2) {
|
|
|
32127
32127
|
server2.registerTool(
|
|
32128
32128
|
"tia_online",
|
|
32129
32129
|
{
|
|
32130
|
-
title: "TIA \u2014
|
|
32131
|
-
description: "
|
|
32130
|
+
title: "TIA \u2014 go online (GATE G4)",
|
|
32131
|
+
description: "Connects ONLINE to the physical PLC. GATE G4: pass confirm:true (after a human confirms it's safe to connect to the target machine); without it, returns a handoff. Maps to POST /plcs/{plc}/online.",
|
|
32132
32132
|
inputSchema: {
|
|
32133
|
-
plc: external_exports.string().describe("
|
|
32134
|
-
connectionMode: external_exports.string().optional().describe("
|
|
32135
|
-
pcInterfaceName: external_exports.string().optional().describe("
|
|
32136
|
-
pcInterfaceNumber: external_exports.number().int().optional().describe("
|
|
32137
|
-
targetInterfaceName: external_exports.string().optional().describe("
|
|
32138
|
-
confirm: external_exports.boolean().optional().describe("G4: true
|
|
32133
|
+
plc: external_exports.string().describe("PLC name"),
|
|
32134
|
+
connectionMode: external_exports.string().optional().describe("connection mode (localized)"),
|
|
32135
|
+
pcInterfaceName: external_exports.string().optional().describe("PG/PC adapter (localized)"),
|
|
32136
|
+
pcInterfaceNumber: external_exports.number().int().optional().describe("adapter number (default 1)"),
|
|
32137
|
+
targetInterfaceName: external_exports.string().optional().describe("target CPU interface"),
|
|
32138
|
+
confirm: external_exports.boolean().optional().describe("G4: true after human confirmation")
|
|
32139
32139
|
}
|
|
32140
32140
|
},
|
|
32141
32141
|
async ({ plc, connectionMode, pcInterfaceName, pcInterfaceNumber, targetInterfaceName, confirm }) => {
|
|
@@ -32146,18 +32146,18 @@ function registerVerificationTools(server2) {
|
|
|
32146
32146
|
server2.registerTool(
|
|
32147
32147
|
"tia_offline",
|
|
32148
32148
|
{
|
|
32149
|
-
title: "TIA \u2014
|
|
32150
|
-
description: "
|
|
32151
|
-
inputSchema: { plc: external_exports.string().describe("
|
|
32149
|
+
title: "TIA \u2014 go offline",
|
|
32150
|
+
description: "Disconnects the PLC from online mode. Maps to POST /plcs/{plc}/offline.",
|
|
32151
|
+
inputSchema: { plc: external_exports.string().describe("PLC name") }
|
|
32152
32152
|
},
|
|
32153
32153
|
async ({ plc }) => send("POST", `/plcs/${seg3(plc)}/offline`)
|
|
32154
32154
|
);
|
|
32155
32155
|
server2.registerTool(
|
|
32156
32156
|
"tia_online_state",
|
|
32157
32157
|
{
|
|
32158
|
-
title: "TIA \u2014
|
|
32159
|
-
description: "
|
|
32160
|
-
inputSchema: { plc: external_exports.string().describe("
|
|
32158
|
+
title: "TIA \u2014 online state",
|
|
32159
|
+
description: "Reads the PLC's online state (online/offline). Read-only (class R). Maps to GET /plcs/{plc}/online/state.",
|
|
32160
|
+
inputSchema: { plc: external_exports.string().describe("PLC name") }
|
|
32161
32161
|
},
|
|
32162
32162
|
async ({ plc }) => {
|
|
32163
32163
|
try {
|
|
@@ -32170,14 +32170,14 @@ function registerVerificationTools(server2) {
|
|
|
32170
32170
|
server2.registerTool(
|
|
32171
32171
|
"tia_accessible_devices",
|
|
32172
32172
|
{
|
|
32173
|
-
title: "TIA \u2014
|
|
32174
|
-
description: "
|
|
32173
|
+
title: "TIA \u2014 accessible devices (GATE G7)",
|
|
32174
|
+
description: "Scans the network via the PG/PC adapter and lists accessible devices \u2014 useful for discovering the localized names of mode/adapter/interface before downloading. GATE G7 (net scan): pass confirm:true. Maps to POST /plcs/{plc}/online/accessibledevices.",
|
|
32175
32175
|
inputSchema: {
|
|
32176
|
-
plc: external_exports.string().describe("
|
|
32177
|
-
connectionMode: external_exports.string().optional().describe("
|
|
32178
|
-
pcInterfaceName: external_exports.string().optional().describe("
|
|
32179
|
-
pcInterfaceNumber: external_exports.number().int().optional().describe("
|
|
32180
|
-
confirm: external_exports.boolean().optional().describe("G7: true
|
|
32176
|
+
plc: external_exports.string().describe("PLC name"),
|
|
32177
|
+
connectionMode: external_exports.string().optional().describe("connection mode (localized)"),
|
|
32178
|
+
pcInterfaceName: external_exports.string().optional().describe("PG/PC adapter (localized)"),
|
|
32179
|
+
pcInterfaceNumber: external_exports.number().int().optional().describe("adapter number (default 1)"),
|
|
32180
|
+
confirm: external_exports.boolean().optional().describe("G7: true after human confirmation")
|
|
32181
32181
|
}
|
|
32182
32182
|
},
|
|
32183
32183
|
async ({ plc, connectionMode, pcInterfaceName, pcInterfaceNumber, confirm }) => {
|
|
@@ -32188,11 +32188,11 @@ function registerVerificationTools(server2) {
|
|
|
32188
32188
|
server2.registerTool(
|
|
32189
32189
|
"tia_mastersecret_set",
|
|
32190
32190
|
{
|
|
32191
|
-
title: "TIA \u2014
|
|
32192
|
-
description: "
|
|
32191
|
+
title: "TIA \u2014 set master secret (GATE G6)",
|
|
32192
|
+
description: "Sets the master secret (password) of a protected CPU, before online/download. GATE G6: the password comes from a HUMAN (or a credential vault) \u2014 the AI NEVER makes it up. (Note: P3.7 questions sending the secret over HTTP in plain text; prefer local entry on the host.) Maps to POST /plcs/{plc}/online/mastersecret.",
|
|
32193
32193
|
inputSchema: {
|
|
32194
|
-
plc: external_exports.string().describe("
|
|
32195
|
-
password: external_exports.string().describe("master secret
|
|
32194
|
+
plc: external_exports.string().describe("PLC name"),
|
|
32195
|
+
password: external_exports.string().describe("master secret provided by a human (NEVER made up by the AI)")
|
|
32196
32196
|
}
|
|
32197
32197
|
},
|
|
32198
32198
|
async ({ plc, password }) => send("POST", `/plcs/${seg3(plc)}/online/mastersecret`, jsonBody3({ password }))
|
|
@@ -32200,9 +32200,9 @@ function registerVerificationTools(server2) {
|
|
|
32200
32200
|
server2.registerTool(
|
|
32201
32201
|
"tia_mastersecret_reset",
|
|
32202
32202
|
{
|
|
32203
|
-
title: "TIA \u2014
|
|
32204
|
-
description: "
|
|
32205
|
-
inputSchema: { plc: external_exports.string().describe("
|
|
32203
|
+
title: "TIA \u2014 reset master secret",
|
|
32204
|
+
description: "Removes/resets the CPU's master secret. Maps to DELETE /plcs/{plc}/online/mastersecret.",
|
|
32205
|
+
inputSchema: { plc: external_exports.string().describe("PLC name") }
|
|
32206
32206
|
},
|
|
32207
32207
|
async ({ plc }) => send("DELETE", `/plcs/${seg3(plc)}/online/mastersecret`)
|
|
32208
32208
|
);
|
|
@@ -32236,15 +32236,15 @@ function ipInCidr(ip, cidr) {
|
|
|
32236
32236
|
function checkUnique(names, rule, what, out) {
|
|
32237
32237
|
const seen = /* @__PURE__ */ new Set();
|
|
32238
32238
|
for (const n of names) {
|
|
32239
|
-
if (seen.has(n)) out.push({ rule, severity: "error", detail:
|
|
32239
|
+
if (seen.has(n)) out.push({ rule, severity: "error", detail: `duplicate ${what}: "${n}" (R-NAMES: names must be unique).` });
|
|
32240
32240
|
seen.add(n);
|
|
32241
32241
|
}
|
|
32242
32242
|
}
|
|
32243
32243
|
function validateSpec(spec) {
|
|
32244
32244
|
const v = [];
|
|
32245
32245
|
const devices = Array.isArray(spec?.devices) ? spec.devices : [];
|
|
32246
|
-
if (!spec?.project?.name) v.push({ rule: "SCHEMA", severity: "error", detail: "project.name
|
|
32247
|
-
if (devices.length === 0) v.push({ rule: "SCHEMA", severity: "error", detail: "devices
|
|
32246
|
+
if (!spec?.project?.name) v.push({ rule: "SCHEMA", severity: "error", detail: "project.name is required." });
|
|
32247
|
+
if (devices.length === 0) v.push({ rule: "SCHEMA", severity: "error", detail: "devices must have \u22651 item." });
|
|
32248
32248
|
checkUnique(devices.map((d) => d?.name).filter(Boolean), "R-NAMES", "device", v);
|
|
32249
32249
|
const subnetNames = [
|
|
32250
32250
|
...spec?.network?.subnet?.name ? [spec.network.subnet.name] : [],
|
|
@@ -32252,26 +32252,26 @@ function validateSpec(spec) {
|
|
|
32252
32252
|
];
|
|
32253
32253
|
checkUnique(subnetNames, "R-NAMES", "subnet", v);
|
|
32254
32254
|
checkUnique((Array.isArray(spec?.dataTypes) ? spec.dataTypes : []).map((u) => u?.name).filter(Boolean), "R-NAMES", "UDT", v);
|
|
32255
|
-
checkUnique((Array.isArray(spec?.blocks) ? spec.blocks : []).map((b) => b?.name).filter(Boolean), "R-NAMES", "
|
|
32255
|
+
checkUnique((Array.isArray(spec?.blocks) ? spec.blocks : []).map((b) => b?.name).filter(Boolean), "R-NAMES", "block", v);
|
|
32256
32256
|
const byTable = /* @__PURE__ */ new Map();
|
|
32257
32257
|
for (const t of Array.isArray(spec?.tags) ? spec.tags : []) {
|
|
32258
32258
|
if (!t?.table || !t?.name) continue;
|
|
32259
32259
|
if (!byTable.has(t.table)) byTable.set(t.table, []);
|
|
32260
32260
|
byTable.get(t.table).push(t.name);
|
|
32261
32261
|
}
|
|
32262
|
-
for (const [table, names] of byTable) checkUnique(names, "R-NAMES", `tag (
|
|
32262
|
+
for (const [table, names] of byTable) checkUnique(names, "R-NAMES", `tag (table ${table})`, v);
|
|
32263
32263
|
for (const d of devices) {
|
|
32264
32264
|
if (d?.typeIdentifier && !TYPEID_RE.test(d.typeIdentifier))
|
|
32265
|
-
v.push({ rule: "R-TYPEID", severity: "error", detail: `device "${d.name}": typeIdentifier
|
|
32265
|
+
v.push({ rule: "R-TYPEID", severity: "error", detail: `device "${d.name}": invalid typeIdentifier "${d.typeIdentifier}" \u2014 use OrderNumber:<MLFB>/V<fw> (slash, not ':V'). Resolve via tia_catalog.` });
|
|
32266
32266
|
for (const m of Array.isArray(d?.modules) ? d.modules : []) {
|
|
32267
32267
|
if (m?.order && !TYPEID_RE.test(m.order))
|
|
32268
|
-
v.push({ rule: "R-TYPEID", severity: "error", detail: `
|
|
32268
|
+
v.push({ rule: "R-TYPEID", severity: "error", detail: `module in "${d.name}": invalid order "${m.order}" \u2014 use OrderNumber:<MLFB>/V<fw>.` });
|
|
32269
32269
|
}
|
|
32270
32270
|
}
|
|
32271
32271
|
for (const d of devices) {
|
|
32272
32272
|
if (d?.family === "S7-1200") {
|
|
32273
32273
|
const sm = (Array.isArray(d?.modules) ? d.modules : []).filter((m) => (m?.kind ?? "SM") === "SM").length;
|
|
32274
|
-
if (sm > 8) v.push({ rule: "R-MODLIMIT", severity: "error", detail: `device "${d.name}" (S7-1200)
|
|
32274
|
+
if (sm > 8) v.push({ rule: "R-MODLIMIT", severity: "error", detail: `device "${d.name}" (S7-1200) has ${sm} SM \u2014 above the limit (8). Confirm the exact limit for the model via tia_catalog.` });
|
|
32275
32275
|
}
|
|
32276
32276
|
}
|
|
32277
32277
|
const families = new Set(devices.filter((d) => d?.role === "cpu" || /^S7-1[25]00$/.test(d?.family ?? "")).map((d) => d?.family).filter(Boolean));
|
|
@@ -32280,8 +32280,8 @@ function validateSpec(spec) {
|
|
|
32280
32280
|
const graphLangs = /* @__PURE__ */ new Set(["STL", "GRAPH"]);
|
|
32281
32281
|
for (const b of Array.isArray(spec?.blocks) ? spec.blocks : []) {
|
|
32282
32282
|
if (graphLangs.has(b?.language)) {
|
|
32283
|
-
if (has1200 && !has1500) v.push({ rule: "R-LANGFAM", severity: "error", detail: `
|
|
32284
|
-
else if (has1200 && has1500) v.push({ rule: "R-LANGFAM", severity: "warning", detail: `
|
|
32283
|
+
if (has1200 && !has1500) v.push({ rule: "R-LANGFAM", severity: "error", detail: `block "${b.name}" uses ${b.language}, which is S7-1500-only, but the target is S7-1200.` });
|
|
32284
|
+
else if (has1200 && has1500) v.push({ rule: "R-LANGFAM", severity: "warning", detail: `block "${b.name}" uses ${b.language} (S7-1500-only) in a project with S7-1200 and S7-1500 \u2014 make sure it targets the 1500 CPU.` });
|
|
32285
32285
|
}
|
|
32286
32286
|
}
|
|
32287
32287
|
const net = spec?.network;
|
|
@@ -32294,31 +32294,31 @@ function validateSpec(spec) {
|
|
|
32294
32294
|
let ioSystemSubnet = null;
|
|
32295
32295
|
let ioSystemCount = 0;
|
|
32296
32296
|
for (const n of nodes) {
|
|
32297
|
-
if (!deviceByName.has(n?.device)) v.push({ rule: "R-SUBNET", severity: "error", detail: `network node
|
|
32297
|
+
if (!deviceByName.has(n?.device)) v.push({ rule: "R-SUBNET", severity: "error", detail: `network node references nonexistent device "${n?.device}".` });
|
|
32298
32298
|
const sName = n?.subnet ?? net?.subnet?.name;
|
|
32299
32299
|
const sub = sName ? subnetByName.get(sName) : void 0;
|
|
32300
|
-
if (!sub) v.push({ rule: "R-SUBNET", severity: "error", detail: `node "${n?.device}"
|
|
32300
|
+
if (!sub) v.push({ rule: "R-SUBNET", severity: "error", detail: `node "${n?.device}" references nonexistent subnet "${sName}".` });
|
|
32301
32301
|
else if (n?.ip && sub?.cidr && !ipInCidr(n.ip, sub.cidr))
|
|
32302
|
-
v.push({ rule: "R-SUBNET", severity: "error", detail: `node "${n?.device}": IP ${n.ip}
|
|
32302
|
+
v.push({ rule: "R-SUBNET", severity: "error", detail: `node "${n?.device}": IP ${n.ip} is outside CIDR ${sub.cidr} of subnet ${sName}.` });
|
|
32303
32303
|
if (n?.createIoSystem) {
|
|
32304
32304
|
ioSystemCount++;
|
|
32305
32305
|
ioSystemSubnet = n?.subnet ?? net?.subnet?.name ?? null;
|
|
32306
32306
|
}
|
|
32307
32307
|
}
|
|
32308
|
-
if (ioSystemCount === 0) v.push({ rule: "R-SUBNET", severity: "warning", detail: "
|
|
32309
|
-
if (ioSystemCount > 1) v.push({ rule: "R-SUBNET", severity: "warning", detail: `${ioSystemCount} nodes
|
|
32308
|
+
if (ioSystemCount === 0) v.push({ rule: "R-SUBNET", severity: "warning", detail: "no node with createIoSystem:true \u2014 one CPU must host the IO-system (\xA73)." });
|
|
32309
|
+
if (ioSystemCount > 1) v.push({ rule: "R-SUBNET", severity: "warning", detail: `${ioSystemCount} nodes with createIoSystem:true \u2014 normally 1 per controller interface.` });
|
|
32310
32310
|
if (ioSystemSubnet) {
|
|
32311
32311
|
for (const n of nodes) {
|
|
32312
32312
|
const dev = deviceByName.get(n?.device);
|
|
32313
32313
|
if (dev?.role === "io-device") {
|
|
32314
32314
|
const sName = n?.subnet ?? net?.subnet?.name;
|
|
32315
|
-
if (sName !== ioSystemSubnet) v.push({ rule: "R-SUBNET", severity: "error", detail: `io-device "${n?.device}"
|
|
32315
|
+
if (sName !== ioSystemSubnet) v.push({ rule: "R-SUBNET", severity: "error", detail: `io-device "${n?.device}" is on subnet "${sName}", different from the IO-system's subnet "${ioSystemSubnet}" (CPU+IO must share the subnet).` });
|
|
32316
32316
|
}
|
|
32317
32317
|
}
|
|
32318
32318
|
}
|
|
32319
32319
|
}
|
|
32320
32320
|
if (spec?.safety?.required === true && spec?.autonomous === true)
|
|
32321
|
-
v.push({ rule: "G5", severity: "error", detail: "safety.required && autonomous \u21D2
|
|
32321
|
+
v.push({ rule: "G5", severity: "error", detail: "safety.required && autonomous \u21D2 REJECTED. Safety logic (F) is NEVER authored/downloaded autonomously (IEC 61511). Selecting an F-CPU is allowed; F authoring is human and gated." });
|
|
32322
32322
|
const counts = {
|
|
32323
32323
|
devices: devices.length,
|
|
32324
32324
|
modules: devices.reduce((a, d) => a + (Array.isArray(d?.modules) ? d.modules.length : 0), 0),
|
|
@@ -32338,8 +32338,8 @@ function planSpec(spec) {
|
|
|
32338
32338
|
const steps = [];
|
|
32339
32339
|
const assumptions = [];
|
|
32340
32340
|
const plc = primaryPlc(spec);
|
|
32341
|
-
assumptions.push(`
|
|
32342
|
-
assumptions.push("
|
|
32341
|
+
assumptions.push(`Target PLC for tags/blocks = "${plc}" (1st device role:cpu; adjust if the PlcSoftware name differs).`);
|
|
32342
|
+
assumptions.push("Precondition: a project must already be OPEN (tia_connect/tia_project_create \u2014 gated G1). UDTs and block LOGIC are not auto-generated from the spec (they declare structure, not code).");
|
|
32343
32343
|
const subnets = [];
|
|
32344
32344
|
if (spec?.network?.subnet) subnets.push(spec.network.subnet);
|
|
32345
32345
|
for (const s of Array.isArray(spec?.subnets) ? spec.subnets : []) subnets.push(s);
|
|
@@ -32347,59 +32347,59 @@ function planSpec(spec) {
|
|
|
32347
32347
|
for (const s of subnets) {
|
|
32348
32348
|
if (!s?.name || subnetSeen.has(s.name)) continue;
|
|
32349
32349
|
subnetSeen.add(s.name);
|
|
32350
|
-
steps.push({ op: "subnet.create", method: "POST", path: "/subnets", body: jsonBody4({ typeIdentifier: s.type ?? "System:Subnet.Ethernet", name: s.name }), summary: `
|
|
32350
|
+
steps.push({ op: "subnet.create", method: "POST", path: "/subnets", body: jsonBody4({ typeIdentifier: s.type ?? "System:Subnet.Ethernet", name: s.name }), summary: `create subnet ${s.name}` });
|
|
32351
32351
|
}
|
|
32352
32352
|
for (const d of Array.isArray(spec?.devices) ? spec.devices : []) {
|
|
32353
|
-
steps.push({ op: "device.create", method: "POST", path: "/devices", body: jsonBody4({ typeIdentifier: d.typeIdentifier, deviceName: d.name }), summary: `
|
|
32353
|
+
steps.push({ op: "device.create", method: "POST", path: "/devices", body: jsonBody4({ typeIdentifier: d.typeIdentifier, deviceName: d.name }), summary: `create device ${d.name}` });
|
|
32354
32354
|
}
|
|
32355
32355
|
for (const d of Array.isArray(spec?.devices) ? spec.devices : []) {
|
|
32356
32356
|
for (const m of Array.isArray(d?.modules) ? d.modules : []) {
|
|
32357
|
-
steps.push({ op: "device.plug", method: "POST", path: `/devices/${seg4(d.name)}/plug`, body: jsonBody4({ typeIdentifier: m.order, position: m.slot }), summary: `
|
|
32357
|
+
steps.push({ op: "device.plug", method: "POST", path: `/devices/${seg4(d.name)}/plug`, body: jsonBody4({ typeIdentifier: m.order, position: m.slot }), summary: `plug module into ${d.name}` });
|
|
32358
32358
|
}
|
|
32359
32359
|
}
|
|
32360
32360
|
for (const n of Array.isArray(spec?.network?.nodes) ? spec.network.nodes : []) {
|
|
32361
32361
|
const sName = n?.subnet ?? spec?.network?.subnet?.name;
|
|
32362
|
-
steps.push({ op: "network.connect", method: "POST", path: "/network/connect", body: jsonBody4({ device: n.device, subnet: sName, ip: n.ip, createIoSystem: n.createIoSystem }), summary: `
|
|
32362
|
+
steps.push({ op: "network.connect", method: "POST", path: "/network/connect", body: jsonBody4({ device: n.device, subnet: sName, ip: n.ip, createIoSystem: n.createIoSystem }), summary: `connect ${n.device} @ ${n.ip} to subnet ${sName}` });
|
|
32363
32363
|
}
|
|
32364
32364
|
if (plc) {
|
|
32365
32365
|
const tableNames = /* @__PURE__ */ new Set();
|
|
32366
32366
|
for (const tt of Array.isArray(spec?.tagTables) ? spec.tagTables : []) if (tt?.name) tableNames.add(tt.name);
|
|
32367
32367
|
for (const t of Array.isArray(spec?.tags) ? spec.tags : []) if (t?.table) tableNames.add(t.table);
|
|
32368
|
-
for (const name of tableNames) steps.push({ op: "tagtable.create", method: "POST", path: `/plcs/${seg4(plc)}/tagtables`, body: { name }, summary: `
|
|
32368
|
+
for (const name of tableNames) steps.push({ op: "tagtable.create", method: "POST", path: `/plcs/${seg4(plc)}/tagtables`, body: { name }, summary: `create tag table ${name}` });
|
|
32369
32369
|
for (const t of Array.isArray(spec?.tags) ? spec.tags : []) {
|
|
32370
|
-
steps.push({ op: "tag.create", method: "POST", path: `/plcs/${seg4(plc)}/tags`, body: jsonBody4({ table: t.table, name: t.name, dataType: t.dataType, address: t.address }), summary: `
|
|
32370
|
+
steps.push({ op: "tag.create", method: "POST", path: `/plcs/${seg4(plc)}/tags`, body: jsonBody4({ table: t.table, name: t.name, dataType: t.dataType, address: t.address }), summary: `create tag ${t.name}:${t.dataType}` });
|
|
32371
32371
|
}
|
|
32372
32372
|
for (const b of Array.isArray(spec?.blocks) ? spec.blocks : []) {
|
|
32373
|
-
if (b?.kind === "FB") steps.push({ op: "fb.create", method: "POST", path: `/plcs/${seg4(plc)}/fbs`, body: jsonBody4({ name: b.name, language: b.language }), summary: `
|
|
32373
|
+
if (b?.kind === "FB") steps.push({ op: "fb.create", method: "POST", path: `/plcs/${seg4(plc)}/fbs`, body: jsonBody4({ name: b.name, language: b.language }), summary: `create FB ${b.name} (${b.language})` });
|
|
32374
32374
|
}
|
|
32375
32375
|
const fcObDb = (Array.isArray(spec?.blocks) ? spec.blocks : []).filter((b) => b?.kind && b.kind !== "FB").map((b) => b.name);
|
|
32376
|
-
if (fcObDb.length) assumptions.push(`
|
|
32376
|
+
if (fcObDb.length) assumptions.push(`OB/FC/DB blocks (${fcObDb.join(", ")}) and their logic are not included in apply \u2014 author them via tia_source_put (SCL) / tia_import_xml (graphical).`);
|
|
32377
32377
|
for (const fu of Array.isArray(spec?.functionalUnits) ? spec.functionalUnits : []) {
|
|
32378
32378
|
for (const em of Array.isArray(fu?.equipmentModules) ? fu.equipmentModules : []) {
|
|
32379
32379
|
for (const cm of Array.isArray(em?.controlModules) ? em.controlModules : []) {
|
|
32380
32380
|
if (cm?.instanceDb && cm?.libraryType) {
|
|
32381
32381
|
const fb = String(cm.libraryType).split("@")[0];
|
|
32382
|
-
steps.push({ op: "instancedb.create", method: "POST", path: `/plcs/${seg4(plc)}/instancedbs`, body: jsonBody4({ name: cm.instanceDb, instanceOf: fb }), summary: `
|
|
32382
|
+
steps.push({ op: "instancedb.create", method: "POST", path: `/plcs/${seg4(plc)}/instancedbs`, body: jsonBody4({ name: cm.instanceDb, instanceOf: fb }), summary: `create iDB ${cm.instanceDb} from ${fb}` });
|
|
32383
32383
|
}
|
|
32384
32384
|
}
|
|
32385
32385
|
}
|
|
32386
32386
|
}
|
|
32387
32387
|
const ladder = Array.isArray(spec?.verification?.ladder) ? spec.verification.ladder : ["compile"];
|
|
32388
|
-
if (ladder.includes("compile")) steps.push({ op: "compile", method: "POST", path: `/plcs/${seg4(plc)}/compile`, body: {}, summary: `
|
|
32388
|
+
if (ladder.includes("compile")) steps.push({ op: "compile", method: "POST", path: `/plcs/${seg4(plc)}/compile`, body: {}, summary: `compile ${plc} (verifier)` });
|
|
32389
32389
|
}
|
|
32390
32390
|
return { steps, assumptions };
|
|
32391
32391
|
}
|
|
32392
32392
|
async function applySpec(spec, opts = {}) {
|
|
32393
32393
|
if (spec?.safety?.required === true && spec?.autonomous === true) {
|
|
32394
|
-
return textResult({ status: "rejected", gate: "safety_signoff", reason: "G5: safety.required && autonomous \u21D2 REJECT (IEC 61511).
|
|
32394
|
+
return textResult({ status: "rejected", gate: "safety_signoff", reason: "G5: safety.required && autonomous \u21D2 REJECT (IEC 61511). Selecting an F-CPU is OK; authoring/downloading F is never autonomous." }, true);
|
|
32395
32395
|
}
|
|
32396
32396
|
const val = validateSpec(spec);
|
|
32397
32397
|
if (!val.valid) {
|
|
32398
|
-
return textResult({ status: "invalid", valid: false, violations: val.violations, counts: val.counts, note: "
|
|
32398
|
+
return textResult({ status: "invalid", valid: false, violations: val.violations, counts: val.counts, note: "Invalid spec \u2014 fix the 'error' violations before applying." }, true);
|
|
32399
32399
|
}
|
|
32400
32400
|
const { steps, assumptions } = planSpec(spec);
|
|
32401
32401
|
if (opts.dryRun) {
|
|
32402
|
-
return textResult({ dryRun: true, status: "plan_ok", valid: true, stepCount: steps.length, steps, assumptions, warnings: val.violations.filter((x) => x.severity === "warning"), note: "
|
|
32402
|
+
return textResult({ dryRun: true, status: "plan_ok", valid: true, stepCount: steps.length, steps, assumptions, warnings: val.violations.filter((x) => x.severity === "warning"), note: "Plan validated. NOTHING was applied. Run with dryRun:false (project open) to build; the download (G3) is NOT included." }, false);
|
|
32403
32403
|
}
|
|
32404
32404
|
const applied = [];
|
|
32405
32405
|
let compileResult = null;
|
|
@@ -32412,20 +32412,20 @@ async function applySpec(spec, opts = {}) {
|
|
|
32412
32412
|
const err = asTiaError(e);
|
|
32413
32413
|
applied.push({ op: s.op, summary: s.summary, ok: false, error: err.message, kind: err.kind });
|
|
32414
32414
|
if (!opts.continueOnError) {
|
|
32415
|
-
return textResult({ status: "stopped", appliedCount: applied.length, applied, stoppedAt: s.summary, error: err.message, kind: err.kind, assumptions, note: "
|
|
32415
|
+
return textResult({ status: "stopped", appliedCount: applied.length, applied, stoppedAt: s.summary, error: err.message, kind: err.kind, assumptions, note: "Stopped at the 1st error (Gd2: re-running converges by name; pass continueOnError:true to keep going despite errors)." }, true);
|
|
32416
32416
|
}
|
|
32417
32417
|
}
|
|
32418
32418
|
}
|
|
32419
32419
|
const okAll = applied.every((a) => a.ok);
|
|
32420
|
-
return textResult({ status: okAll ? "applied" : "applied_with_errors", appliedCount: applied.length, applied, compile: compileResult, assumptions, warnings: val.violations.filter((x) => x.severity === "warning"), nextHints: ["
|
|
32420
|
+
return textResult({ status: okAll ? "applied" : "applied_with_errors", appliedCount: applied.length, applied, compile: compileResult, assumptions, warnings: val.violations.filter((x) => x.severity === "warning"), nextHints: ["Offline build complete. To deploy: review the compile, then tia_download (GATE G3, requires human approval)."] }, !okAll);
|
|
32421
32421
|
}
|
|
32422
32422
|
function registerSpecTools(server2) {
|
|
32423
32423
|
server2.registerTool(
|
|
32424
32424
|
"tia_spec_validate",
|
|
32425
32425
|
{
|
|
32426
|
-
title: "TIA \u2014
|
|
32427
|
-
description: "
|
|
32428
|
-
inputSchema: { spec: external_exports.record(external_exports.string(), external_exports.unknown()).describe("
|
|
32426
|
+
title: "TIA \u2014 validate project-spec (deterministic, R)",
|
|
32427
|
+
description: "Validates a project-spec (docs/TIA-BEST-PRACTICES \xA713.2) deterministically, WITHOUT touching serve (rung 0): R-NAMES (unique names), R-TYPEID (OrderNumber:<MLFB>/V<fw>), R-SUBNET (IP\u2208CIDR, same subnet, 1 IO-system), R-LANGFAM (STL/GRAPH S7-1500 only), R-MODLIMIT, and G5 (safety.required && autonomous \u21D2 REJECT). Returns { valid, violations:[{rule,severity,detail}], counts }.",
|
|
32428
|
+
inputSchema: { spec: external_exports.record(external_exports.string(), external_exports.unknown()).describe("the project-spec (object conforming to the plugin's JSON Schema)") }
|
|
32429
32429
|
},
|
|
32430
32430
|
async ({ spec }) => {
|
|
32431
32431
|
const r = validateSpec(spec);
|
|
@@ -32435,9 +32435,9 @@ function registerSpecTools(server2) {
|
|
|
32435
32435
|
server2.registerTool(
|
|
32436
32436
|
"tia_spec_plan",
|
|
32437
32437
|
{
|
|
32438
|
-
title: "TIA \u2014
|
|
32439
|
-
description: "
|
|
32440
|
-
inputSchema: { spec: external_exports.record(external_exports.string(), external_exports.unknown()).describe("
|
|
32438
|
+
title: "TIA \u2014 plan project-spec (without applying)",
|
|
32439
|
+
description: "Validates and transforms a project-spec into the ORDERED SEQUENCE of offline operations (subnets\u2192devices\u2192modules\u2192network\u2192tags\u2192blocks\u2192compile), WITHOUT touching serve. Gated operations (connect/download) are NOT included. Returns { steps, assumptions } or the violations if invalid.",
|
|
32440
|
+
inputSchema: { spec: external_exports.record(external_exports.string(), external_exports.unknown()).describe("the project-spec") }
|
|
32441
32441
|
},
|
|
32442
32442
|
async ({ spec }) => {
|
|
32443
32443
|
const val = validateSpec(spec);
|
|
@@ -32449,12 +32449,12 @@ function registerSpecTools(server2) {
|
|
|
32449
32449
|
server2.registerTool(
|
|
32450
32450
|
"tia_spec_apply",
|
|
32451
32451
|
{
|
|
32452
|
-
title: "TIA \u2014
|
|
32453
|
-
description: "
|
|
32452
|
+
title: "TIA \u2014 apply project-spec (offline orchestrator)",
|
|
32453
|
+
description: "Orchestrates the OFFLINE build of a project-spec on an ALREADY OPEN project: validates \u2192 G5 (rejects safety+autonomous) \u2192 serially executes subnets/devices/modules/network/tags/blocks \u2192 compiles. STOPS at the 1st error (continueOnError to keep going). NEVER downloads (download is GATE G3, always human). dryRun:true returns the plan without applying. Requires an open project (tia_connect/tia_project_create beforehand).",
|
|
32454
32454
|
inputSchema: {
|
|
32455
|
-
spec: external_exports.record(external_exports.string(), external_exports.unknown()).describe("
|
|
32456
|
-
dryRun: external_exports.boolean().optional().describe("true \u2192
|
|
32457
|
-
continueOnError: external_exports.boolean().optional().describe("true \u2192
|
|
32455
|
+
spec: external_exports.record(external_exports.string(), external_exports.unknown()).describe("the project-spec"),
|
|
32456
|
+
dryRun: external_exports.boolean().optional().describe("true \u2192 returns the plan without applying"),
|
|
32457
|
+
continueOnError: external_exports.boolean().optional().describe("true \u2192 does not stop at the 1st error (Gd2: re-running converges by name)")
|
|
32458
32458
|
}
|
|
32459
32459
|
},
|
|
32460
32460
|
async ({ spec, dryRun, continueOnError }) => applySpec(spec, { dryRun, continueOnError })
|
|
@@ -32462,12 +32462,12 @@ function registerSpecTools(server2) {
|
|
|
32462
32462
|
}
|
|
32463
32463
|
|
|
32464
32464
|
// src/index.ts
|
|
32465
|
-
var server = new McpServer({ name: "tia-openness", version: "1.
|
|
32465
|
+
var server = new McpServer({ name: "tia-openness", version: "1.2.0" });
|
|
32466
32466
|
server.registerTool(
|
|
32467
32467
|
"tia_ping",
|
|
32468
32468
|
{
|
|
32469
|
-
title: "TIA \u2014
|
|
32470
|
-
description: "
|
|
32469
|
+
title: "TIA \u2014 connection diagnostics",
|
|
32470
|
+
description: "Diagnoses connectivity to the TIA Openness `serve` API and whether the server is ACTIVATED. Tests GET /health (reachability) and GET /readiness (license activation). Ideal for the MCP-on-Mac-pointing-at-a-`serve`-on-a-Windows-VM scenario. Read-only. Returns { base, reachable, activated, latencyMs, hint }.",
|
|
32471
32471
|
inputSchema: {}
|
|
32472
32472
|
},
|
|
32473
32473
|
async () => {
|
|
@@ -32506,8 +32506,8 @@ server.registerTool(
|
|
|
32506
32506
|
server.registerTool(
|
|
32507
32507
|
"tia_readiness",
|
|
32508
32508
|
{
|
|
32509
|
-
title: "TIA \u2014
|
|
32510
|
-
description: "
|
|
32509
|
+
title: "TIA \u2014 environment readiness",
|
|
32510
|
+
description: "Readiness diagnostic for the TIA Openness V21 environment ON THE SERVE HOST (x64 process, Windows 'Siemens TIA Openness' group, PublicAPI, 21.0 registry key, and TIA instances). Call BEFORE connecting. Maps to GET /readiness. Read-only (class R). Returns { ready, checks:[{ name, status, detail, remediation }] }.",
|
|
32511
32511
|
inputSchema: {}
|
|
32512
32512
|
},
|
|
32513
32513
|
async () => {
|
|
@@ -32528,9 +32528,9 @@ registerSpecTools(server);
|
|
|
32528
32528
|
async function main() {
|
|
32529
32529
|
const transport = new StdioServerTransport();
|
|
32530
32530
|
await server.connect(transport);
|
|
32531
|
-
console.error(`[tia-openness-mcp] stdio
|
|
32531
|
+
console.error(`[tia-openness-mcp] stdio ready. API base = ${BASE} timeout=${TIMEOUT_MS}ms`);
|
|
32532
32532
|
}
|
|
32533
32533
|
main().catch((e) => {
|
|
32534
|
-
console.error("[tia-openness-mcp]
|
|
32534
|
+
console.error("[tia-openness-mcp] fatal error:", e);
|
|
32535
32535
|
process.exit(1);
|
|
32536
32536
|
});
|