@codesys/mcp-toolkit 1.1.2 → 1.1.3
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/server.js +57 -61
- package/docs/configuration.md +141 -119
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* IMPORTANT: This server receives configuration as parameters from bin.ts,
|
|
8
8
|
* which helps avoid issues with command-line argument passing in different execution environments.
|
|
9
|
-
* (Incorporates script templates from v1.6.9)
|
|
9
|
+
* (Incorporates script templates from v1.6.9 and improved tool descriptions)
|
|
10
10
|
*/
|
|
11
11
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
12
|
if (k2 === undefined) k2 = k;
|
|
@@ -122,7 +122,11 @@ function startMcpServer(config) {
|
|
|
122
122
|
const server = new mcp_js_1.McpServer({
|
|
123
123
|
name: "CODESYS Control MCP Server",
|
|
124
124
|
version: "1.7.1", // Update version as needed
|
|
125
|
-
capabilities: {
|
|
125
|
+
capabilities: {
|
|
126
|
+
// Explicitly declare capabilities - enables listChanged notifications if supported by SDK
|
|
127
|
+
resources: { listChanged: true }, // Assuming you might want to notify if resources change dynamically
|
|
128
|
+
tools: { listChanged: true } // Assuming you might want to notify if tools change dynamically (less common)
|
|
129
|
+
}
|
|
126
130
|
});
|
|
127
131
|
console.error("SERVER.TS: McpServer instance created.");
|
|
128
132
|
// --- End MCP Server Initialization ---
|
|
@@ -1165,27 +1169,31 @@ except Exception as e:
|
|
|
1165
1169
|
}));
|
|
1166
1170
|
// --- End Resources ---
|
|
1167
1171
|
// --- Tools ---
|
|
1168
|
-
server.tool("open_project",
|
|
1172
|
+
server.tool("open_project", // Tool Name
|
|
1173
|
+
"Opens an existing CODESYS project file.", // Tool Description
|
|
1174
|
+
{
|
|
1175
|
+
filePath: zod_1.z.string().describe("Path to the project file (e.g., 'C:/Projects/MyPLC.project' or '/Users/user/projects/my_project.project').")
|
|
1176
|
+
}, (args) => __awaiter(this, void 0, void 0, function* () {
|
|
1169
1177
|
const { filePath } = args;
|
|
1170
1178
|
let absPath = path.normalize(path.isAbsolute(filePath) ? filePath : path.join(WORKSPACE_DIR, filePath));
|
|
1171
1179
|
console.error(`Tool call: open_project: ${absPath}`);
|
|
1172
1180
|
try {
|
|
1173
1181
|
const escapedPath = absPath.replace(/\\/g, '\\\\');
|
|
1174
|
-
// *** DEFINE script ***
|
|
1175
1182
|
const script = OPEN_PROJECT_SCRIPT_TEMPLATE.replace("{PROJECT_FILE_PATH}", escapedPath);
|
|
1176
|
-
// *** END DEFINE script ***
|
|
1177
1183
|
const result = yield (0, codesys_interop_1.executeCodesysScript)(script, codesysExePath, codesysProfileName);
|
|
1178
1184
|
const success = result.success && result.output.includes("SCRIPT_SUCCESS");
|
|
1179
|
-
// **** RETURN MCP STRUCTURE ****
|
|
1180
1185
|
return { content: [{ type: "text", text: success ? `Project opened: ${absPath}` : `Failed open project ${absPath}. Output:\n${result.output}` }], isError: !success };
|
|
1181
1186
|
}
|
|
1182
1187
|
catch (e) {
|
|
1183
1188
|
console.error(`Error open_project ${absPath}: ${e}`);
|
|
1184
|
-
// **** RETURN MCP STRUCTURE ****
|
|
1185
1189
|
return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
|
|
1186
1190
|
}
|
|
1187
1191
|
}));
|
|
1188
|
-
server.tool("create_project",
|
|
1192
|
+
server.tool("create_project", // Tool Name
|
|
1193
|
+
"Creates a new CODESYS project from the standard template.", // Tool Description
|
|
1194
|
+
{
|
|
1195
|
+
filePath: zod_1.z.string().describe("Path where the new project file should be created (e.g., 'C:/Projects/NewPLC.project' or '/Users/user/projects/new_project.project').")
|
|
1196
|
+
}, (args) => __awaiter(this, void 0, void 0, function* () {
|
|
1189
1197
|
const { filePath } = args;
|
|
1190
1198
|
let absPath = path.normalize(path.isAbsolute(filePath) ? filePath : path.join(WORKSPACE_DIR, filePath));
|
|
1191
1199
|
console.error(`Tool call: create_project (copy template): ${absPath}`);
|
|
@@ -1222,56 +1230,53 @@ except Exception as e:
|
|
|
1222
1230
|
}
|
|
1223
1231
|
catch (e) {
|
|
1224
1232
|
console.error(`Template Error: ${e.message}`);
|
|
1225
|
-
// **** RETURN MCP STRUCTURE ****
|
|
1226
1233
|
return { content: [{ type: "text", text: `Template Error: ${e.message}` }], isError: true };
|
|
1227
1234
|
}
|
|
1228
1235
|
try {
|
|
1229
1236
|
const escProjPath = absPath.replace(/\\/g, '\\\\');
|
|
1230
1237
|
const escTmplPath = templatePath.replace(/\\/g, '\\\\');
|
|
1231
|
-
// *** DEFINE script ***
|
|
1232
1238
|
const script = CREATE_PROJECT_SCRIPT_TEMPLATE
|
|
1233
1239
|
.replace("{PROJECT_FILE_PATH}", escProjPath)
|
|
1234
1240
|
.replace("{TEMPLATE_PROJECT_PATH}", escTmplPath);
|
|
1235
|
-
// *** END DEFINE script ***
|
|
1236
1241
|
console.error(">>> create_project (copy-then-open): PREPARED SCRIPT:", script.substring(0, 500) + "...");
|
|
1237
1242
|
const result = yield (0, codesys_interop_1.executeCodesysScript)(script, codesysExePath, codesysProfileName);
|
|
1238
1243
|
console.error(">>> create_project (copy-then-open): EXECUTION RESULT:", JSON.stringify(result));
|
|
1239
1244
|
const success = result.success && result.output.includes("SCRIPT_SUCCESS");
|
|
1240
|
-
// **** RETURN MCP STRUCTURE ****
|
|
1241
1245
|
return { content: [{ type: "text", text: success ? `Project created from template: ${absPath}` : `Failed create project ${absPath} from template. Output:\n${result.output}` }], isError: !success };
|
|
1242
1246
|
}
|
|
1243
1247
|
catch (e) {
|
|
1244
1248
|
console.error(`Error create_project ${absPath}: ${e}`);
|
|
1245
|
-
// **** RETURN MCP STRUCTURE ****
|
|
1246
1249
|
return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
|
|
1247
1250
|
}
|
|
1248
1251
|
}));
|
|
1249
|
-
server.tool("save_project",
|
|
1252
|
+
server.tool("save_project", // Tool Name
|
|
1253
|
+
"Saves the currently open CODESYS project.", // Tool Description
|
|
1254
|
+
{
|
|
1255
|
+
projectFilePath: zod_1.z.string().describe("Path to the project file to ensure is open before saving (e.g., 'C:/Projects/MyPLC.project').")
|
|
1256
|
+
}, (args) => __awaiter(this, void 0, void 0, function* () {
|
|
1250
1257
|
const { projectFilePath } = args;
|
|
1251
1258
|
let absPath = path.normalize(path.isAbsolute(projectFilePath) ? projectFilePath : path.join(WORKSPACE_DIR, projectFilePath));
|
|
1252
1259
|
console.error(`Tool call: save_project: ${absPath}`);
|
|
1253
1260
|
try {
|
|
1254
1261
|
const escapedPath = absPath.replace(/\\/g, '\\\\');
|
|
1255
|
-
// *** DEFINE script ***
|
|
1256
1262
|
const script = SAVE_PROJECT_SCRIPT_TEMPLATE.replace("{PROJECT_FILE_PATH}", escapedPath);
|
|
1257
|
-
// *** END DEFINE script ***
|
|
1258
1263
|
const result = yield (0, codesys_interop_1.executeCodesysScript)(script, codesysExePath, codesysProfileName);
|
|
1259
1264
|
const success = result.success && result.output.includes("SCRIPT_SUCCESS");
|
|
1260
|
-
// **** RETURN MCP STRUCTURE ****
|
|
1261
1265
|
return { content: [{ type: "text", text: success ? `Project saved: ${absPath}` : `Failed save project ${absPath}. Output:\n${result.output}` }], isError: !success };
|
|
1262
1266
|
}
|
|
1263
1267
|
catch (e) {
|
|
1264
1268
|
console.error(`Error save_project ${absPath}: ${e}`);
|
|
1265
|
-
// **** RETURN MCP STRUCTURE ****
|
|
1266
1269
|
return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
|
|
1267
1270
|
}
|
|
1268
1271
|
}));
|
|
1269
|
-
server.tool("create_pou",
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
+
server.tool("create_pou", // Tool Name
|
|
1273
|
+
"Creates a new Program, Function Block, or Function POU within the specified CODESYS project.", // Tool Description
|
|
1274
|
+
{
|
|
1275
|
+
projectFilePath: zod_1.z.string().describe("Path to the project file (e.g., 'C:/Projects/MyPLC.project')."),
|
|
1276
|
+
name: zod_1.z.string().describe("Name for the new POU (must be a valid IEC identifier)."),
|
|
1272
1277
|
type: PouTypeEnum.describe("Type of POU (Program, FunctionBlock, Function)."),
|
|
1273
|
-
language: ImplementationLanguageEnum.describe("Implementation language (ST, LD, FBD, etc.).
|
|
1274
|
-
parentPath: zod_1.z.string().describe("Relative path under project
|
|
1278
|
+
language: ImplementationLanguageEnum.describe("Implementation language (ST, LD, FBD, etc.). CODESYS default will be used if specific language is not set or directly supported by scripting for this POU type."),
|
|
1279
|
+
parentPath: zod_1.z.string().describe("Relative path under project root or application where the POU should be created (e.g., 'Application' or 'MyFolder/SubFolder').")
|
|
1275
1280
|
}, (args) => __awaiter(this, void 0, void 0, function* () {
|
|
1276
1281
|
const { projectFilePath, name, type, language, parentPath } = args;
|
|
1277
1282
|
let absPath = path.normalize(path.isAbsolute(projectFilePath) ? projectFilePath : path.join(WORKSPACE_DIR, projectFilePath));
|
|
@@ -1280,31 +1285,29 @@ except Exception as e:
|
|
|
1280
1285
|
console.error(`Tool call: create_pou: Name='${sanName}', Type='${type}', Lang='${language}', Parent='${sanParentPath}', Project='${absPath}'`);
|
|
1281
1286
|
try {
|
|
1282
1287
|
const escProjPath = absPath.replace(/\\/g, '\\\\');
|
|
1283
|
-
// *** DEFINE script ***
|
|
1284
1288
|
let script = CREATE_POU_SCRIPT_TEMPLATE.replace("{PROJECT_FILE_PATH}", escProjPath);
|
|
1285
1289
|
script = script.replace("{POU_NAME}", sanName);
|
|
1286
1290
|
script = script.replace("{POU_TYPE_STR}", type);
|
|
1287
1291
|
script = script.replace("{IMPL_LANGUAGE_STR}", language);
|
|
1288
1292
|
script = script.replace("{PARENT_PATH}", sanParentPath);
|
|
1289
|
-
// *** END DEFINE script ***
|
|
1290
1293
|
console.error(">>> create_pou: PREPARED SCRIPT:", script.substring(0, 500) + "...");
|
|
1291
1294
|
const result = yield (0, codesys_interop_1.executeCodesysScript)(script, codesysExePath, codesysProfileName);
|
|
1292
1295
|
console.error(">>> create_pou: EXECUTION RESULT:", JSON.stringify(result));
|
|
1293
1296
|
const success = result.success && result.output.includes("SCRIPT_SUCCESS");
|
|
1294
|
-
// **** RETURN MCP STRUCTURE ****
|
|
1295
1297
|
return { content: [{ type: "text", text: success ? `POU '${sanName}' created in '${sanParentPath}' of ${absPath}. Project saved.` : `Failed create POU '${sanName}'. Output:\n${result.output}` }], isError: !success };
|
|
1296
1298
|
}
|
|
1297
1299
|
catch (e) {
|
|
1298
1300
|
console.error(`Error create_pou ${sanName} in ${absPath}: ${e}`);
|
|
1299
|
-
// **** RETURN MCP STRUCTURE ****
|
|
1300
1301
|
return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
|
|
1301
1302
|
}
|
|
1302
1303
|
}));
|
|
1303
|
-
server.tool("set_pou_code",
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1304
|
+
server.tool("set_pou_code", // Tool Name
|
|
1305
|
+
"Sets the declaration and/or implementation code for a specific POU, Method, or Property.", // Tool Description
|
|
1306
|
+
{
|
|
1307
|
+
projectFilePath: zod_1.z.string().describe("Path to the project file (e.g., 'C:/Projects/MyPLC.project')."),
|
|
1308
|
+
pouPath: zod_1.z.string().describe("Full relative path to the target object (e.g., 'Application/MyPOU', 'MyFolder/MyFB/MyMethod', 'MyFolder/MyFB/MyProperty')."),
|
|
1309
|
+
declarationCode: zod_1.z.string().describe("Code for the declaration part (VAR...END_VAR). If omitted, the declaration is not changed.").optional(),
|
|
1310
|
+
implementationCode: zod_1.z.string().describe("Code for the implementation logic part. If omitted, the implementation is not changed.").optional()
|
|
1308
1311
|
}, (args) => __awaiter(this, void 0, void 0, function* () {
|
|
1309
1312
|
const { projectFilePath, pouPath, declarationCode, implementationCode } = args;
|
|
1310
1313
|
if (declarationCode === undefined && implementationCode === undefined) {
|
|
@@ -1318,29 +1321,28 @@ except Exception as e:
|
|
|
1318
1321
|
// Escape content for Python triple-quoted strings
|
|
1319
1322
|
const sanDeclCode = (declarationCode !== null && declarationCode !== void 0 ? declarationCode : "").replace(/\\/g, '\\\\').replace(/"""/g, '\\"\\"\\"');
|
|
1320
1323
|
const sanImplCode = (implementationCode !== null && implementationCode !== void 0 ? implementationCode : "").replace(/\\/g, '\\\\').replace(/"""/g, '\\"\\"\\"');
|
|
1321
|
-
// *** DEFINE script ***
|
|
1322
1324
|
let script = SET_POU_CODE_SCRIPT_TEMPLATE.replace("{PROJECT_FILE_PATH}", escProjPath);
|
|
1323
1325
|
script = script.replace("{POU_FULL_PATH}", sanPouPath);
|
|
1324
1326
|
script = script.replace("{DECLARATION_CONTENT}", sanDeclCode);
|
|
1325
1327
|
script = script.replace("{IMPLEMENTATION_CONTENT}", sanImplCode);
|
|
1326
|
-
// *** END DEFINE script ***
|
|
1327
1328
|
console.error(">>> set_pou_code: PREPARED SCRIPT:", script.substring(0, 500) + "...");
|
|
1328
1329
|
const result = yield (0, codesys_interop_1.executeCodesysScript)(script, codesysExePath, codesysProfileName);
|
|
1329
1330
|
console.error(">>> set_pou_code: EXECUTION RESULT:", JSON.stringify(result));
|
|
1330
1331
|
const success = result.success && result.output.includes("SCRIPT_SUCCESS");
|
|
1331
|
-
// **** RETURN MCP STRUCTURE ****
|
|
1332
1332
|
return { content: [{ type: "text", text: success ? `Code set for '${sanPouPath}' in ${absPath}. Project saved.` : `Failed set code for '${sanPouPath}'. Output:\n${result.output}` }], isError: !success };
|
|
1333
1333
|
}
|
|
1334
1334
|
catch (e) {
|
|
1335
1335
|
console.error(`Error set_pou_code ${sanPouPath} in ${absPath}: ${e}`);
|
|
1336
|
-
// **** RETURN MCP STRUCTURE ****
|
|
1337
1336
|
return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
|
|
1338
1337
|
}
|
|
1339
1338
|
}));
|
|
1340
|
-
server.tool("create_property",
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1339
|
+
server.tool("create_property", // Tool Name
|
|
1340
|
+
"Creates a new Property within a specific Function Block POU.", // Tool Description
|
|
1341
|
+
{
|
|
1342
|
+
projectFilePath: zod_1.z.string().describe("Path to the project file (e.g., 'C:/Projects/MyPLC.project')."),
|
|
1343
|
+
// Assuming properties can only be added to FBs in standard CODESYS scripting
|
|
1344
|
+
parentPouPath: zod_1.z.string().describe("Relative path to the parent Function Block POU (e.g., 'Application/MyFB')."),
|
|
1345
|
+
propertyName: zod_1.z.string().describe("Name for the new property (must be a valid IEC identifier)."),
|
|
1344
1346
|
propertyType: zod_1.z.string().describe("Data type of the property (e.g., 'BOOL', 'INT', 'MyDUT').")
|
|
1345
1347
|
}, (args) => __awaiter(this, void 0, void 0, function* () {
|
|
1346
1348
|
const { projectFilePath, parentPouPath, propertyName, propertyType } = args;
|
|
@@ -1350,22 +1352,18 @@ except Exception as e:
|
|
|
1350
1352
|
const sanPropType = propertyType.trim();
|
|
1351
1353
|
console.error(`Tool call: create_property: Name='${sanPropName}', Type='${sanPropType}', ParentPOU='${sanParentPath}', Project='${absPath}'`);
|
|
1352
1354
|
if (!sanPropName || !sanPropType) {
|
|
1353
|
-
// **** RETURN MCP STRUCTURE ****
|
|
1354
1355
|
return { content: [{ type: "text", text: `Error: Property name and type cannot be empty.` }], isError: true };
|
|
1355
1356
|
}
|
|
1356
1357
|
try {
|
|
1357
1358
|
const escProjPath = absPath.replace(/\\/g, '\\\\');
|
|
1358
|
-
// *** DEFINE script ***
|
|
1359
1359
|
let script = CREATE_PROPERTY_SCRIPT_TEMPLATE.replace("{PROJECT_FILE_PATH}", escProjPath);
|
|
1360
1360
|
script = script.replace("{PARENT_POU_FULL_PATH}", sanParentPath);
|
|
1361
1361
|
script = script.replace("{PROPERTY_NAME}", sanPropName);
|
|
1362
1362
|
script = script.replace("{PROPERTY_TYPE}", sanPropType);
|
|
1363
|
-
// *** END DEFINE script ***
|
|
1364
1363
|
console.error(">>> create_property: PREPARED SCRIPT:", script.substring(0, 500) + "...");
|
|
1365
1364
|
const result = yield (0, codesys_interop_1.executeCodesysScript)(script, codesysExePath, codesysProfileName);
|
|
1366
1365
|
console.error(">>> create_property: EXECUTION RESULT:", JSON.stringify(result));
|
|
1367
1366
|
const success = result.success && result.output.includes("SCRIPT_SUCCESS");
|
|
1368
|
-
// **** RETURN MCP STRUCTURE ****
|
|
1369
1367
|
return {
|
|
1370
1368
|
content: [{ type: "text", text: success ? `Property '${sanPropName}' created under '${sanParentPath}' in ${absPath}. Project saved.` : `Failed to create property '${sanPropName}'. Output:\n${result.output}` }],
|
|
1371
1369
|
isError: !success
|
|
@@ -1373,15 +1371,17 @@ except Exception as e:
|
|
|
1373
1371
|
}
|
|
1374
1372
|
catch (e) {
|
|
1375
1373
|
console.error(`Error create_property ${sanPropName} in ${absPath}: ${e}`);
|
|
1376
|
-
// **** RETURN MCP STRUCTURE ****
|
|
1377
1374
|
return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
|
|
1378
1375
|
}
|
|
1379
1376
|
}));
|
|
1380
|
-
server.tool("create_method",
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1377
|
+
server.tool("create_method", // Tool Name
|
|
1378
|
+
"Creates a new Method within a specific Function Block POU.", // Tool Description
|
|
1379
|
+
{
|
|
1380
|
+
projectFilePath: zod_1.z.string().describe("Path to the project file (e.g., 'C:/Projects/MyPLC.project')."),
|
|
1381
|
+
// Assuming methods can typically only be added to FBs in standard CODESYS scripting
|
|
1382
|
+
parentPouPath: zod_1.z.string().describe("Relative path to the parent Function Block POU (e.g., 'Application/MyFB')."),
|
|
1383
|
+
methodName: zod_1.z.string().describe("Name of the new method (must be a valid IEC identifier)."),
|
|
1384
|
+
returnType: zod_1.z.string().optional().describe("Return type (e.g., 'BOOL', 'INT'). Leave empty or omit for no return value (PROCEDURE)."),
|
|
1385
1385
|
}, (args) => __awaiter(this, void 0, void 0, function* () {
|
|
1386
1386
|
const { projectFilePath, parentPouPath, methodName, returnType } = args;
|
|
1387
1387
|
let absPath = path.normalize(path.isAbsolute(projectFilePath) ? projectFilePath : path.join(WORKSPACE_DIR, projectFilePath));
|
|
@@ -1390,22 +1390,18 @@ except Exception as e:
|
|
|
1390
1390
|
const sanReturnType = (returnType !== null && returnType !== void 0 ? returnType : "").trim();
|
|
1391
1391
|
console.error(`Tool call: create_method: Name='${sanMethName}', Return='${sanReturnType}', ParentPOU='${sanParentPath}', Project='${absPath}'`);
|
|
1392
1392
|
if (!sanMethName) {
|
|
1393
|
-
// **** RETURN MCP STRUCTURE ****
|
|
1394
1393
|
return { content: [{ type: "text", text: `Error: Method name cannot be empty.` }], isError: true };
|
|
1395
1394
|
}
|
|
1396
1395
|
try {
|
|
1397
1396
|
const escProjPath = absPath.replace(/\\/g, '\\\\');
|
|
1398
|
-
// *** DEFINE script ***
|
|
1399
1397
|
let script = CREATE_METHOD_SCRIPT_TEMPLATE.replace("{PROJECT_FILE_PATH}", escProjPath);
|
|
1400
1398
|
script = script.replace("{PARENT_POU_FULL_PATH}", sanParentPath);
|
|
1401
1399
|
script = script.replace("{METHOD_NAME}", sanMethName);
|
|
1402
1400
|
script = script.replace("{RETURN_TYPE}", sanReturnType);
|
|
1403
|
-
// *** END DEFINE script ***
|
|
1404
1401
|
console.error(">>> create_method: PREPARED SCRIPT:", script.substring(0, 500) + "...");
|
|
1405
1402
|
const result = yield (0, codesys_interop_1.executeCodesysScript)(script, codesysExePath, codesysProfileName);
|
|
1406
1403
|
console.error(">>> create_method: EXECUTION RESULT:", JSON.stringify(result));
|
|
1407
1404
|
const success = result.success && result.output.includes("SCRIPT_SUCCESS");
|
|
1408
|
-
// **** RETURN MCP STRUCTURE ****
|
|
1409
1405
|
return {
|
|
1410
1406
|
content: [{ type: "text", text: success ? `Method '${sanMethName}' created under '${sanParentPath}' in ${absPath}. Project saved.` : `Failed to create method '${sanMethName}'. Output:\n${result.output}` }],
|
|
1411
1407
|
isError: !success
|
|
@@ -1413,36 +1409,36 @@ except Exception as e:
|
|
|
1413
1409
|
}
|
|
1414
1410
|
catch (e) {
|
|
1415
1411
|
console.error(`Error create_method ${sanMethName} in ${absPath}: ${e}`);
|
|
1416
|
-
// **** RETURN MCP STRUCTURE ****
|
|
1417
1412
|
return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
|
|
1418
1413
|
}
|
|
1419
1414
|
}));
|
|
1420
|
-
server.tool("compile_project",
|
|
1415
|
+
server.tool("compile_project", // Tool Name
|
|
1416
|
+
"Compiles (Builds) the primary application within a CODESYS project.", // Tool Description
|
|
1417
|
+
{
|
|
1418
|
+
projectFilePath: zod_1.z.string().describe("Path to the project file containing the application to compile (e.g., 'C:/Projects/MyPLC.project').")
|
|
1419
|
+
}, (args) => __awaiter(this, void 0, void 0, function* () {
|
|
1421
1420
|
const { projectFilePath } = args;
|
|
1422
1421
|
let absPath = path.normalize(path.isAbsolute(projectFilePath) ? projectFilePath : path.join(WORKSPACE_DIR, projectFilePath));
|
|
1423
1422
|
console.error(`Tool call: compile_project: ${absPath}`);
|
|
1424
1423
|
try {
|
|
1425
1424
|
const escapedPath = absPath.replace(/\\/g, '\\\\');
|
|
1426
|
-
// *** DEFINE script ***
|
|
1427
1425
|
const script = COMPILE_PROJECT_SCRIPT_TEMPLATE.replace("{PROJECT_FILE_PATH}", escapedPath);
|
|
1428
|
-
// *** END DEFINE script ***
|
|
1429
1426
|
const result = yield (0, codesys_interop_1.executeCodesysScript)(script, codesysExePath, codesysProfileName);
|
|
1430
1427
|
const success = result.success && result.output.includes("SCRIPT_SUCCESS");
|
|
1428
|
+
// Check for actual compile errors in the output log
|
|
1431
1429
|
const hasCompileErrors = result.output.includes("Compile complete --") && !/ 0 error\(s\),/.test(result.output);
|
|
1432
1430
|
let message = success ? `Compilation initiated for application in ${absPath}. Check CODESYS messages for results.` : `Failed initiating compilation for ${absPath}. Output:\n${result.output}`;
|
|
1433
1431
|
let isError = !success; // Base error status on script success
|
|
1434
1432
|
if (success && hasCompileErrors) {
|
|
1435
1433
|
message += " WARNING: Build command reported errors in the output log.";
|
|
1436
1434
|
console.warn("Compile project reported build errors in the output.");
|
|
1437
|
-
//
|
|
1435
|
+
// Report as error if compile fails, even if script technically succeeded
|
|
1438
1436
|
isError = true;
|
|
1439
1437
|
}
|
|
1440
|
-
// **** RETURN MCP STRUCTURE ****
|
|
1441
1438
|
return { content: [{ type: "text", text: message }], isError: isError };
|
|
1442
1439
|
}
|
|
1443
1440
|
catch (e) {
|
|
1444
1441
|
console.error(`Error compile_project ${absPath}: ${e}`);
|
|
1445
|
-
// **** RETURN MCP STRUCTURE ****
|
|
1446
1442
|
return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
|
|
1447
1443
|
}
|
|
1448
1444
|
}));
|
package/docs/configuration.md
CHANGED
|
@@ -1,119 +1,141 @@
|
|
|
1
|
-
# Configuration Guide
|
|
2
|
-
|
|
3
|
-
This guide explains how to configure the CODESYS MCP Toolkit with MCP clients.
|
|
4
|
-
|
|
5
|
-
## Claude Desktop Configuration
|
|
6
|
-
|
|
7
|
-
Claude Desktop is a popular MCP client that can use the CODESYS MCP Toolkit.
|
|
8
|
-
|
|
9
|
-
### Finding the Configuration File
|
|
10
|
-
|
|
11
|
-
The configuration file is located at:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
**
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
-
|
|
1
|
+
# Configuration Guide
|
|
2
|
+
|
|
3
|
+
This guide explains how to configure the CODESYS MCP Toolkit for use with MCP clients, specifically focusing on Claude Desktop.
|
|
4
|
+
|
|
5
|
+
## Claude Desktop Configuration
|
|
6
|
+
|
|
7
|
+
Claude Desktop is a popular MCP client that can use the CODESYS MCP Toolkit.
|
|
8
|
+
|
|
9
|
+
### Finding the Configuration File
|
|
10
|
+
|
|
11
|
+
The configuration file is typically located at:
|
|
12
|
+
* **Windows:** `C:\Users\<YourUsername>\AppData\Roaming\Claude\settings.json` (or `claude_desktop_config.json` in older versions)
|
|
13
|
+
* **macOS:** `~/Library/Application Support/Claude/settings.json` (or `claude_desktop_config.json`)
|
|
14
|
+
* **Linux:** `~/.config/Claude/settings.json` (or `claude_desktop_config.json`)
|
|
15
|
+
|
|
16
|
+
*(If you can't find `settings.json`, look for `claude_desktop_config.json`)*
|
|
17
|
+
|
|
18
|
+
### Recommended Configuration: Direct Command
|
|
19
|
+
|
|
20
|
+
Due to potential environment variable issues (especially with `PATH`) when launching Node.js tools via wrappers like `npx` within certain host applications (e.g., Claude Desktop), it is **strongly recommended** to configure Claude Desktop to run the installed command `codesys-mcp-tool` **directly**.
|
|
21
|
+
|
|
22
|
+
Edit the configuration file and add the CODESYS MCP server to the `mcpServers` object:
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"mcpServers": {
|
|
27
|
+
// ... other servers ...
|
|
28
|
+
"codesys_local": {
|
|
29
|
+
"command": "codesys-mcp-tool", // <<< Use the direct command name
|
|
30
|
+
"args": [
|
|
31
|
+
// Pass arguments directly to the tool using flags
|
|
32
|
+
"--codesys-path", "C:\\Program Files\\Path\\To\\Your\\CODESYS\\Common\\CODESYS.exe", // Customize this path!
|
|
33
|
+
"--codesys-profile", "Your CODESYS Profile Name" // Customize this profile name!
|
|
34
|
+
// Optional: Add --workspace "/path/to/your/projects" if needed
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
// ... other servers ...
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Why Direct Command is Recommended
|
|
43
|
+
|
|
44
|
+
Launching with `npx` (`"command": "npx"`) has been observed to cause errors (`'C:\Program' is not recognized...` or profile errors) when run from within applications like Claude Desktop. This is likely due to `npx` altering the execution environment (like the `PATH` variable) in a way that interferes with how CODESYS finds its own components or parses arguments when run non-interactively. Using the globally installed `codesys-mcp-tool` command directly avoids this interference.
|
|
45
|
+
|
|
46
|
+
### Customizing for Your Environment
|
|
47
|
+
|
|
48
|
+
You **must** customize:
|
|
49
|
+
1. `--codesys-path`: Set this value to the **full and correct path** of your specific `CODESYS.exe` executable file.
|
|
50
|
+
2. `--codesys-profile`: Set this value to the **exact name** of the CODESYS profile you want to use (this name is visible in the CODESYS UI or start menu).
|
|
51
|
+
|
|
52
|
+
**Important Notes:**
|
|
53
|
+
* Use double backslashes (`\\`) for paths in the JSON file if you are on Windows.
|
|
54
|
+
* The profile name must match *exactly*, including capitalization and spacing.
|
|
55
|
+
* Ensure `codesys-mcp-tool` is accessible in the system PATH where Claude Desktop runs. Global installation via `npm install -g` usually handles this.
|
|
56
|
+
|
|
57
|
+
### Applying Changes
|
|
58
|
+
|
|
59
|
+
After modifying the configuration:
|
|
60
|
+
1. Save the `settings.json` file.
|
|
61
|
+
2. **Restart Claude Desktop completely** (ensure it's fully closed and reopened).
|
|
62
|
+
3. Claude should now attempt to connect to the CODESYS MCP server using the direct command.
|
|
63
|
+
|
|
64
|
+
### Alternative (Not Recommended): Using `npx`
|
|
65
|
+
|
|
66
|
+
If you cannot use the direct command method for some reason, you can try `npx`, but be aware of the potential issues mentioned above.
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
// Example using npx (POTENTIALLY PROBLEMATIC - USE WITH CAUTION):
|
|
70
|
+
{
|
|
71
|
+
"mcpServers": {
|
|
72
|
+
"codesys_local": {
|
|
73
|
+
"command": "npx",
|
|
74
|
+
"args": [
|
|
75
|
+
"-y", // Tells npx to install temporarily if not found globally
|
|
76
|
+
"@codesys/mcp-toolkit",
|
|
77
|
+
// Arguments for the tool MUST come AFTER the package name
|
|
78
|
+
"--codesys-path", "C:\\Program Files\\Path\\To\\Your\\CODESYS\\Common\\CODESYS.exe",
|
|
79
|
+
"--codesys-profile", "Your CODESYS Profile Name"
|
|
80
|
+
// Optional: "--workspace", "/path/to/your/projects"
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
*If you encounter errors with `npx`, switch to the recommended Direct Command method.*
|
|
87
|
+
|
|
88
|
+
## Command-Line Options (for `codesys-mcp-tool`)
|
|
89
|
+
|
|
90
|
+
When running `codesys-mcp-tool` directly or configuring it in your MCP client, you can use these arguments:
|
|
91
|
+
|
|
92
|
+
* `-p, --codesys-path <path>`: Full path to `CODESYS.exe`. (Required, overrides `CODESYS_PATH` env var, has a default but relying on it is not recommended).
|
|
93
|
+
* `-f, --codesys-profile <profile>`: Name of the CODESYS profile. (Required, overrides `CODESYS_PROFILE` env var, has a default but relying on it is not recommended).
|
|
94
|
+
* `-w, --workspace <dir>`: Workspace directory for resolving relative project paths passed to tools. Defaults to the directory where the command was launched (which might be unpredictable when run by another application). Setting this explicitly might be needed if using relative paths.
|
|
95
|
+
* `-V, --version`: Output the version number.
|
|
96
|
+
* `-h, --help`: Display help for command.
|
|
97
|
+
|
|
98
|
+
## Verifying Configuration
|
|
99
|
+
|
|
100
|
+
To verify your configuration within Claude Desktop:
|
|
101
|
+
|
|
102
|
+
1. After restarting Claude with the correct configuration, wait for the server to connect (check logs if needed).
|
|
103
|
+
2. Ask Claude:
|
|
104
|
+
```
|
|
105
|
+
Can you please check the status of the CODESYS Local server?
|
|
106
|
+
```
|
|
107
|
+
(Replace `CODESYS Local` if you used a different key in `mcpServers`).
|
|
108
|
+
|
|
109
|
+
3. Claude should use the `codesys://project/status` resource. A successful response will show information like `Scripting OK: true`, `Project Open: ...`, etc. An error indicates a problem with the connection, CODESYS setup, or the script execution itself (check logs).
|
|
110
|
+
|
|
111
|
+
## Multiple CODESYS Installations
|
|
112
|
+
|
|
113
|
+
If you have multiple CODESYS installations, you can create multiple server entries in `mcpServers` with different keys (names) and point each to the specific installation:
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"mcpServers": {
|
|
118
|
+
"codesys_sp21": { // Unique key for this server
|
|
119
|
+
"command": "codesys-mcp-tool", // Direct command
|
|
120
|
+
"args": [
|
|
121
|
+
"--codesys-path", "C:\\Program Files\\CODESYS 3.5.21.0\\CODESYS\\Common\\CODESYS.exe",
|
|
122
|
+
"--codesys-profile", "CODESYS V3.5 SP21"
|
|
123
|
+
]
|
|
124
|
+
},
|
|
125
|
+
"codesys_sp19": { // Unique key for this server
|
|
126
|
+
"command": "codesys-mcp-tool", // Direct command
|
|
127
|
+
"args": [
|
|
128
|
+
"--codesys-path", "C:\\Program Files\\CODESYS 3.5.19.0\\CODESYS\\Common\\CODESYS.exe",
|
|
129
|
+
"--codesys-profile", "CODESYS V3.5 SP19"
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
// ... other servers ...
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Next Steps
|
|
138
|
+
|
|
139
|
+
* Try some [basic examples](examples.md)
|
|
140
|
+
* Learn about the [available tools and resources](api.md)
|
|
141
|
+
* Check the [troubleshooting guide](troubleshooting.md) if you encounter issues
|