@codesys/mcp-toolkit 1.5.2 → 1.5.5

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.
@@ -20,7 +20,9 @@
20
20
  "Bash(ls:*)",
21
21
  "Bash(ls:*)",
22
22
  "Bash(mkdir:*)",
23
- "Bash(mkdir:*)"
23
+ "Bash(mkdir:*)",
24
+ "Bash(node:*)",
25
+ "Bash(node:*)"
24
26
  ],
25
27
  "deny": []
26
28
  }
package/CHANGELOG.md CHANGED
@@ -5,6 +5,25 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.5.5] - 2025-05-02
9
+ ### Fixed
10
+ - Added enhanced command.json file verification to debug session communication
11
+ - Improved logging for command file operations to diagnose IPC issues
12
+ - Added command data verification to detect potential file corruption
13
+
14
+ ## [1.5.4] - 2025-05-02
15
+ ### Fixed
16
+ - Added `--no-session` flag to disable session management when CODESYS UI hangs
17
+ - Improved session handling with better error detection and user feedback
18
+ - Removed hardcoded session disable flag in favor of command-line option
19
+ - Added safeguards to prevent UI blocking during session operations
20
+
21
+ ## [1.5.3] - 2025-05-02
22
+ ### Fixed
23
+ - Added automatic session startup when server starts
24
+ - Improved session detection with better diagnostics
25
+ - Enhanced logging for session command status
26
+
8
27
  ## [1.5.2] - 2025-05-02
9
28
  ### Fixed
10
29
  - Re-enabled session management feature that was disabled for debugging
package/dist/bin.js CHANGED
@@ -38,6 +38,8 @@ commander_1.program
38
38
  // Add workspace option if needed, defaults to cwd
39
39
  .option('-w, --workspace <dir>', 'Workspace directory for relative project paths', process.cwd() // Default to current working directory
40
40
  )
41
+ // Add option to disable session management
42
+ .option('--no-session', 'Disable session management (use one-time script execution only)', false)
41
43
  .parse(process.argv); // Parse the arguments
42
44
  const options = commander_1.program.opts();
43
45
  // --- Log the options Commander parsed ---
@@ -54,8 +56,10 @@ console.error(`========================================`);
54
56
  const serverConfig = {
55
57
  codesysPath: options.codesysPath.trim(),
56
58
  profileName: options.codesysProfile.trim(),
57
- workspaceDir: options.workspace.trim() // Pass workspace dir
59
+ workspaceDir: options.workspace.trim(), // Pass workspace dir
60
+ enableSessionManagement: options.session // Determined by --no-session flag (default: true)
58
61
  };
62
+ console.error(`BIN.TS: Session management is ${serverConfig.enableSessionManagement ? 'enabled' : 'disabled'}`);
59
63
  // --- End Prepare Config ---
60
64
  // --- Call the server setup function ---
61
65
  console.error("BIN.TS: Calling startMcpServer...");
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+ /**
3
+ * Session Path Diagnostic Tool
4
+ * This script checks the consistency of paths used in the session management system.
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ const path = __importStar(require("path"));
41
+ const os = __importStar(require("os"));
42
+ const fs = __importStar(require("fs"));
43
+ // Session directory paths from direct_session_command.ts
44
+ const DIRECT_SESSION_DIR = path.join(os.tmpdir(), 'codesys_session');
45
+ const DIRECT_COMMAND_FILE = path.join(DIRECT_SESSION_DIR, 'command.json');
46
+ const DIRECT_RESULT_FILE = path.join(DIRECT_SESSION_DIR, 'result.json');
47
+ const DIRECT_SESSION_LOCK_FILE = path.join(DIRECT_SESSION_DIR, 'session.lock');
48
+ const DIRECT_STATE_FILE = path.join(DIRECT_SESSION_DIR, 'session_state.json');
49
+ // Constants from sessionManager.ts
50
+ const SESSION_DIR = path.join(os.tmpdir(), 'codesys_session');
51
+ const COMMAND_FILE = 'command.json';
52
+ const RESULT_FILE = 'result.json';
53
+ const STATE_FILE = 'session_state.json';
54
+ const SESSION_LOCK_FILE = 'session.lock';
55
+ console.log("==== Session Path Diagnostics ====");
56
+ console.log("\nBase session directory check:");
57
+ console.log(`- DIRECT_SESSION_DIR: ${DIRECT_SESSION_DIR}`);
58
+ console.log(`- SESSION_DIR: ${SESSION_DIR}`);
59
+ console.log(` Direct and manager directories match: ${DIRECT_SESSION_DIR === SESSION_DIR}`);
60
+ console.log("\nExpected file paths in direct_session_command.ts:");
61
+ console.log(`- Command file: ${DIRECT_COMMAND_FILE}`);
62
+ console.log(`- Result file: ${DIRECT_RESULT_FILE}`);
63
+ console.log(`- Lock file: ${DIRECT_SESSION_LOCK_FILE}`);
64
+ console.log(`- State file: ${DIRECT_STATE_FILE}`);
65
+ console.log("\nFile names in sessionManager.ts:");
66
+ console.log(`- Command file: ${COMMAND_FILE}`);
67
+ console.log(`- Result file: ${RESULT_FILE}`);
68
+ console.log(`- Lock file: ${SESSION_LOCK_FILE}`);
69
+ console.log(`- State file: ${STATE_FILE}`);
70
+ console.log("\nFile existence checks:");
71
+ console.log(`- Base session directory exists: ${fs.existsSync(SESSION_DIR)}`);
72
+ if (fs.existsSync(SESSION_DIR)) {
73
+ console.log(`- Command file exists: ${fs.existsSync(DIRECT_COMMAND_FILE)}`);
74
+ console.log(`- Result file exists: ${fs.existsSync(DIRECT_RESULT_FILE)}`);
75
+ console.log(`- Lock file exists: ${fs.existsSync(DIRECT_SESSION_LOCK_FILE)}`);
76
+ console.log(`- State file exists: ${fs.existsSync(DIRECT_STATE_FILE)}`);
77
+ console.log("\nContent checks (if files exist):");
78
+ if (fs.existsSync(DIRECT_COMMAND_FILE)) {
79
+ try {
80
+ const commandContent = fs.readFileSync(DIRECT_COMMAND_FILE, 'utf8');
81
+ console.log(`- Command file content: ${commandContent.substring(0, 150)}...`);
82
+ try {
83
+ const commandJson = JSON.parse(commandContent);
84
+ console.log(` Status: ${commandJson.status}`);
85
+ console.log(` Has command object: ${commandJson.command !== null}`);
86
+ if (commandJson.command) {
87
+ console.log(` Command type: ${commandJson.command.type}`);
88
+ }
89
+ }
90
+ catch (e) {
91
+ console.log(` Error parsing command file JSON: ${e}`);
92
+ }
93
+ }
94
+ catch (e) {
95
+ console.log(`- Error reading command file: ${e}`);
96
+ }
97
+ }
98
+ if (fs.existsSync(DIRECT_RESULT_FILE)) {
99
+ try {
100
+ const resultContent = fs.readFileSync(DIRECT_RESULT_FILE, 'utf8');
101
+ console.log(`- Result file content: ${resultContent.substring(0, 150)}...`);
102
+ try {
103
+ const resultJson = JSON.parse(resultContent);
104
+ console.log(` Status: ${resultJson.status}`);
105
+ console.log(` Has result object: ${resultJson.result !== null}`);
106
+ }
107
+ catch (e) {
108
+ console.log(` Error parsing result file JSON: ${e}`);
109
+ }
110
+ }
111
+ catch (e) {
112
+ console.log(`- Error reading result file: ${e}`);
113
+ }
114
+ }
115
+ if (fs.existsSync(DIRECT_SESSION_LOCK_FILE)) {
116
+ try {
117
+ const lockContent = fs.readFileSync(DIRECT_SESSION_LOCK_FILE, 'utf8');
118
+ console.log(`- Lock file content: ${lockContent}`);
119
+ const lockTime = parseFloat(lockContent);
120
+ const currentTime = Date.now() / 1000; // convert to seconds
121
+ const lockAgeSeconds = currentTime - lockTime;
122
+ console.log(` Lock age: ${lockAgeSeconds.toFixed(1)} seconds`);
123
+ }
124
+ catch (e) {
125
+ console.log(`- Error reading lock file: ${e}`);
126
+ }
127
+ }
128
+ if (fs.existsSync(DIRECT_STATE_FILE)) {
129
+ try {
130
+ const stateContent = fs.readFileSync(DIRECT_STATE_FILE, 'utf8');
131
+ console.log(`- State file content: ${stateContent.substring(0, 150)}...`);
132
+ try {
133
+ const stateJson = JSON.parse(stateContent);
134
+ console.log(` Session ID: ${stateJson.sessionId || stateJson.session_id}`);
135
+ console.log(` Status: ${stateJson.status}`);
136
+ }
137
+ catch (e) {
138
+ console.log(` Error parsing state file JSON: ${e}`);
139
+ }
140
+ }
141
+ catch (e) {
142
+ console.log(`- Error reading state file: ${e}`);
143
+ }
144
+ }
145
+ }
146
+ else {
147
+ console.log(" Cannot check files as base directory does not exist");
148
+ }
149
+ console.log("\n==== End of Session Path Diagnostics ====");
@@ -91,10 +91,10 @@ function executeCodesysScript(scriptContent, codesysExePath, codesysProfileName,
91
91
  if (!fs.existsSync(codesysExePath))
92
92
  throw new Error(`CODESYS executable not found at provided path: ${codesysExePath}`);
93
93
  // --- End Pre-checks ---
94
- // Session management feature control
95
- const SESSION_FEATURE_DISABLED = false; // Session feature enabled
94
+ // Session management feature is now fully controlled by the presence of sessionManager
95
+ // No need for a separate flag as server.ts will set sessionManager to undefined if disabled
96
96
  // --- Check if we should use the persistent session ---
97
- if (!SESSION_FEATURE_DISABLED && sessionManager) {
97
+ if (sessionManager) {
98
98
  const sessionState = sessionManager.getState();
99
99
  // Check if the session is active
100
100
  if (sessionState === sessionManager_1.SessionState.RUNNING || sessionState === sessionManager_1.SessionState.BUSY) {
@@ -141,9 +141,6 @@ function executeCodesysScript(scriptContent, codesysExePath, codesysProfileName,
141
141
  process.stderr.write(`INTEROP: Session not in RUNNING/BUSY state (current: ${sessionState}). Using one-time execution.\n`);
142
142
  }
143
143
  }
144
- else if (SESSION_FEATURE_DISABLED) {
145
- process.stderr.write(`INTEROP: Session feature is disabled. Using one-time execution mode.\n`);
146
- }
147
144
  else {
148
145
  process.stderr.write(`INTEROP: No session manager provided. Using one-time execution mode.\n`);
149
146
  }
@@ -69,19 +69,24 @@ const STATE_FILE = path.join(SESSION_DIR, 'session_state.json');
69
69
  */
70
70
  function isSessionActive() {
71
71
  try {
72
+ // Log the paths we're checking to help with debugging
73
+ console.error(`DIRECT_SESSION: Checking for active session...`);
74
+ console.error(`DIRECT_SESSION: SESSION_DIR: ${SESSION_DIR}`);
75
+ console.error(`DIRECT_SESSION: SESSION_LOCK_FILE: ${SESSION_LOCK_FILE}`);
76
+ console.error(`DIRECT_SESSION: COMMAND_FILE: ${COMMAND_FILE}`);
72
77
  // Check if session directory exists
73
78
  if (!fs.existsSync(SESSION_DIR)) {
74
- console.error(`SESSION_DIR doesn't exist: ${SESSION_DIR}`);
79
+ console.error(`DIRECT_SESSION: SESSION_DIR doesn't exist: ${SESSION_DIR}`);
75
80
  return false;
76
81
  }
77
82
  // Check if lock file exists
78
83
  if (!fs.existsSync(SESSION_LOCK_FILE)) {
79
- console.error(`SESSION_LOCK_FILE doesn't exist: ${SESSION_LOCK_FILE}`);
84
+ console.error(`DIRECT_SESSION: SESSION_LOCK_FILE doesn't exist: ${SESSION_LOCK_FILE}`);
80
85
  return false;
81
86
  }
82
87
  // Check if command file exists
83
88
  if (!fs.existsSync(COMMAND_FILE)) {
84
- console.error(`COMMAND_FILE doesn't exist: ${COMMAND_FILE}`);
89
+ console.error(`DIRECT_SESSION: COMMAND_FILE doesn't exist: ${COMMAND_FILE}`);
85
90
  return false;
86
91
  }
87
92
  // Read the lock file to check age
@@ -89,15 +94,27 @@ function isSessionActive() {
89
94
  const lockTime = parseFloat(lockFileContent);
90
95
  const currentTime = Date.now() / 1000; // convert to seconds
91
96
  const lockAgeSeconds = currentTime - lockTime;
97
+ console.error(`DIRECT_SESSION: Lock file age: ${lockAgeSeconds.toFixed(1)} seconds`);
92
98
  // If lock is too old, session might be dead
93
99
  if (lockAgeSeconds > 30) {
94
- console.error(`Session lock file is too old (${lockAgeSeconds.toFixed(1)} seconds)`);
100
+ console.error(`DIRECT_SESSION: Session lock file is too old (${lockAgeSeconds.toFixed(1)} seconds)`);
95
101
  return false;
96
102
  }
103
+ // Try to read the command file to verify it's in the expected format
104
+ try {
105
+ const commandContent = fs.readFileSync(COMMAND_FILE, 'utf8');
106
+ const commandData = JSON.parse(commandContent);
107
+ console.error(`DIRECT_SESSION: Command file status: ${commandData.status}`);
108
+ }
109
+ catch (cmdError) {
110
+ console.error(`DIRECT_SESSION: Error parsing command file: ${cmdError}`);
111
+ return false;
112
+ }
113
+ console.error(`DIRECT_SESSION: Session appears to be active`);
97
114
  return true;
98
115
  }
99
116
  catch (error) {
100
- console.error(`Error checking session: ${error}`);
117
+ console.error(`DIRECT_SESSION: Error checking session: ${error}`);
101
118
  return false;
102
119
  }
103
120
  }
@@ -126,9 +143,24 @@ function executeScriptDirect(scriptContent_1) {
126
143
  timestamp: Date.now()
127
144
  };
128
145
  console.error(`DIRECT_SESSION: Writing command to ${COMMAND_FILE}`);
129
- // Write command to file
130
- fs.writeFileSync(COMMAND_FILE, JSON.stringify(commandData, null, 2));
131
- console.error(`DIRECT_SESSION: Command written to file`);
146
+ console.error(`DIRECT_SESSION: Command data: ${JSON.stringify(commandData)}`);
147
+ try {
148
+ // Write command to file
149
+ fs.writeFileSync(COMMAND_FILE, JSON.stringify(commandData, null, 2));
150
+ console.error(`DIRECT_SESSION: Command written to file`);
151
+ // Verify the file was written correctly
152
+ try {
153
+ const verifyContent = fs.readFileSync(COMMAND_FILE, 'utf8');
154
+ console.error(`DIRECT_SESSION: Verification - Command file now contains: ${verifyContent.substring(0, 100)}...`);
155
+ }
156
+ catch (verifyErr) {
157
+ console.error(`DIRECT_SESSION: Verification failed - could not read command file: ${verifyErr}`);
158
+ }
159
+ }
160
+ catch (writeErr) {
161
+ console.error(`DIRECT_SESSION: ERROR writing command file: ${writeErr}`);
162
+ throw writeErr; // Re-throw to propagate the error
163
+ }
132
164
  // Poll for result
133
165
  return new Promise((resolve, reject) => {
134
166
  let pollCount = 0;
package/dist/server.js CHANGED
@@ -117,8 +117,39 @@ function startMcpServer(config) {
117
117
  }
118
118
  // --- End Helper Function ---
119
119
  // --- Initialize Session Manager ---
120
- const sessionManager = new sessionManager_1.CodesysSessionManager(codesysExePath, codesysProfileName);
121
- console.error('SERVER.TS: Session manager initialized');
120
+ // Default to true if not specified
121
+ const enableSessionManagement = config.enableSessionManagement !== false;
122
+ console.error(`SERVER.TS: Session management is ${enableSessionManagement ? 'enabled' : 'disabled'}`);
123
+ // Create session manager instance
124
+ let sessionManager;
125
+ if (enableSessionManagement) {
126
+ sessionManager = new sessionManager_1.CodesysSessionManager(codesysExePath, codesysProfileName);
127
+ console.error('SERVER.TS: Session manager initialized');
128
+ // Only start a session if explicitly enabled
129
+ try {
130
+ // Check if session is already active
131
+ console.error('SERVER.TS: Checking if session is already active...');
132
+ const isActive = (0, direct_session_command_1.isSessionActive)();
133
+ if (isActive) {
134
+ console.error('SERVER.TS: Session is already active');
135
+ }
136
+ else {
137
+ console.error('SERVER.TS: Session not active, starting new session...');
138
+ console.error('SERVER.TS: IMPORTANT: If CODESYS hangs during session startup, use --no-session flag');
139
+ yield sessionManager.startSession();
140
+ console.error('SERVER.TS: Session start initiated');
141
+ }
142
+ }
143
+ catch (error) {
144
+ console.error(`SERVER.TS: Error starting session: ${error.message}`);
145
+ console.error('SERVER.TS: Will fallback to one-time execution for operations');
146
+ // Continue without session, will fallback to one-time execution
147
+ }
148
+ }
149
+ else {
150
+ console.error('SERVER.TS: Session management is disabled, will use one-time script execution');
151
+ sessionManager = undefined;
152
+ }
122
153
  // --- End Session Manager Initialization ---
123
154
  // --- Preload script templates ---
124
155
  try {
@@ -639,8 +639,24 @@ class CodesysSessionManager extends events_1.EventEmitter {
639
639
  };
640
640
  // Send the command by writing to the command file
641
641
  console.error(`SESSION_MANAGER: Writing command to file ${this.commandFilePath}`);
642
- fs.writeFileSync(this.commandFilePath, JSON.stringify(commandData, null, 2));
643
- console.error(`SESSION_MANAGER: Command written to file`);
642
+ console.error(`SESSION_MANAGER: Command data: ${JSON.stringify(commandData)}`);
643
+ try {
644
+ // Write command to file
645
+ fs.writeFileSync(this.commandFilePath, JSON.stringify(commandData, null, 2));
646
+ console.error(`SESSION_MANAGER: Command written to file`);
647
+ // Verify the file was written correctly
648
+ try {
649
+ const verifyContent = fs.readFileSync(this.commandFilePath, 'utf8');
650
+ console.error(`SESSION_MANAGER: Verification - Command file now contains: ${verifyContent.substring(0, 100)}...`);
651
+ }
652
+ catch (verifyErr) {
653
+ console.error(`SESSION_MANAGER: Verification failed - could not read command file: ${verifyErr}`);
654
+ }
655
+ }
656
+ catch (writeErr) {
657
+ console.error(`SESSION_MANAGER: ERROR writing command file: ${writeErr}`);
658
+ throw writeErr; // Re-throw to propagate the error
659
+ }
644
660
  // Start reading the result file
645
661
  this.readResultFile(scriptId);
646
662
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codesys/mcp-toolkit",
3
- "version": "1.5.2",
3
+ "version": "1.5.5",
4
4
  "description": "Model Context Protocol (MCP) server for CODESYS automation platform",
5
5
  "main": "dist/server.js",
6
6
  "bin": {