@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 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: { resources: {}, tools: {} }
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", { filePath: zod_1.z.string().describe("Path to the project file.") }, (args) => __awaiter(this, void 0, void 0, function* () {
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", { filePath: zod_1.z.string().describe("Path for new project.") }, (args) => __awaiter(this, void 0, void 0, function* () {
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", { projectFilePath: zod_1.z.string().describe("Path to project.") }, (args) => __awaiter(this, void 0, void 0, function* () {
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
- projectFilePath: zod_1.z.string().describe("Path to project."),
1271
- name: zod_1.z.string().describe("Name for the new POU."),
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.). Will use default if not directly supported/mapped by script."),
1274
- parentPath: zod_1.z.string().describe("Relative path under project/application (e.g., 'Application' or 'MyFolder/SubFolder').")
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
- projectFilePath: zod_1.z.string().describe("Path to project."),
1305
- pouPath: zod_1.z.string().describe("Relative POU/Method/Property path (e.g., 'Application/MyPOU' or 'MyFolder/MyFB/MyMethod')."),
1306
- declarationCode: zod_1.z.string().describe("Code for the declaration part (VAR...END_VAR).").optional(),
1307
- implementationCode: zod_1.z.string().describe("Code for the implementation logic part.").optional()
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
- projectFilePath: zod_1.z.string().describe("Path to the project file."),
1342
- parentPouPath: zod_1.z.string().describe("Relative path to the parent POU (e.g., 'Application/MyFB')."),
1343
- propertyName: zod_1.z.string().describe("Name of the new property."),
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
- projectFilePath: zod_1.z.string().describe("Path to the project file."),
1382
- parentPouPath: zod_1.z.string().describe("Relative path to the parent POU (e.g., 'Application/MyFB')."),
1383
- methodName: zod_1.z.string().describe("Name of the new method."),
1384
- returnType: zod_1.z.string().optional().describe("Return type (e.g., 'BOOL', 'INT'). Leave empty or omit for no return value."),
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", { projectFilePath: zod_1.z.string().describe("Path to project.") }, (args) => __awaiter(this, void 0, void 0, function* () {
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
- // Optionally set isError = true here if compile errors should fail the tool call
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
  }));
@@ -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
- - Windows: `C:\Users\<YourUsername>\AppData\Roaming\Claude\claude_desktop_config.json`
13
- - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
14
-
15
- ### Adding the CODESYS MCP Server Entry
16
-
17
- Edit the configuration file and add the CODESYS MCP server to the `mcpServers` object:
18
-
19
- ```json
20
- {
21
- "mcpServers": {
22
- "codesys_local": {
23
- "command": "npx",
24
- "args": [
25
- "-y",
26
- "@codesys/mcp-toolkit",
27
- "--codesys-path", "C:\\Program Files\\CODESYS 3.5.21.0\\CODESYS\\Common\\CODESYS.exe",
28
- "--codesys-profile", "CODESYS V3.5 SP21"
29
- ]
30
- }
31
- }
32
- }
33
- ```
34
-
35
- ### Configuration Parameters
36
-
37
- - `command`: Use `npx` to execute the package
38
- - `args`: Array of arguments
39
- - `-y`: Automatically accept npm install prompts
40
- - `@codesys/mcp-toolkit`: The package name
41
- - `--codesys-path`: Path to your CODESYS.exe
42
- - `--codesys-profile`: Your CODESYS profile name
43
-
44
- ### Customizing for Your Environment
45
-
46
- You must customize:
47
- 1. `--codesys-path`: Set to the actual path of your CODESYS executable
48
- 2. `--codesys-profile`: Set to the exact name of your CODESYS profile
49
-
50
- **Important Notes:**
51
- - Use double backslashes (`\\`) in Windows paths in JSON
52
- - The profile name must match exactly what appears in CODESYS
53
-
54
- ### Applying Changes
55
-
56
- After modifying the configuration:
57
- 1. Save the file
58
- 2. Restart Claude Desktop completely
59
- 3. Claude should now have access to the CODESYS MCP server
60
-
61
- ## Command-Line Options
62
-
63
- When using the toolkit directly, the following options are available:
64
-
65
- ```
66
- Usage: codesys-mcp-toolkit [options]
67
-
68
- Options:
69
- -V, --version output the version number
70
- -e, --codesys-path <path> Path to CODESYS executable
71
- -p, --codesys-profile <profile> CODESYS profile name
72
- -h, --help display help for command
73
- ```
74
-
75
- ## Verifying Configuration
76
-
77
- To verify your configuration:
78
-
79
- 1. In Claude Desktop, ask:
80
- ```
81
- Can you please check the status of the CODESYS Local server?
82
- ```
83
-
84
- 2. Claude should use the `project-status` resource and return information about the CODESYS server connection.
85
-
86
- ## Multiple CODESYS Installations
87
-
88
- If you have multiple CODESYS installations, you can create multiple server entries with different names:
89
-
90
- ```json
91
- {
92
- "mcpServers": {
93
- "codesys_3_5_21": {
94
- "command": "npx",
95
- "args": [
96
- "-y",
97
- "@codesys/mcp-toolkit",
98
- "--codesys-path", "C:\\Program Files\\CODESYS 3.5.21.0\\CODESYS\\Common\\CODESYS.exe",
99
- "--codesys-profile", "CODESYS V3.5 SP21"
100
- ]
101
- },
102
- "codesys_3_5_19": {
103
- "command": "npx",
104
- "args": [
105
- "-y",
106
- "@codesys/mcp-toolkit",
107
- "--codesys-path", "C:\\Program Files\\CODESYS 3.5.19.0\\CODESYS\\Common\\CODESYS.exe",
108
- "--codesys-profile", "CODESYS V3.5 SP19"
109
- ]
110
- }
111
- }
112
- }
113
- ```
114
-
115
- ## Next Steps
116
-
117
- - Try some [basic examples](examples.md)
118
- - Learn about the [available tools and resources](api.md)
119
- - Check the [troubleshooting guide](troubleshooting.md) if you encounter issues
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codesys/mcp-toolkit",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "description": "Model Context Protocol (MCP) server for CODESYS automation platform",
5
5
  "main": "dist/server.js",
6
6
  "bin": {