@codesys/mcp-toolkit 1.1.4 → 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/.claude/settings.local.json +23 -0
- package/CHANGELOG.md +32 -26
- package/CLAUDE.md +26 -0
- package/CONTRIBUTING.md +72 -72
- package/LICENSE +21 -21
- package/README.md +152 -145
- package/README.md.enhanced +155 -155
- package/codesys-mcp-toolkit-1.2.0.tgz +0 -0
- package/dist/codesys_interop.js +29 -2
- package/dist/server.js +124 -11
- package/dist/sessionManager.js +401 -0
- package/docs/index.md +26 -26
- package/docs/installation.md +84 -84
- package/docs/session_management.md +84 -0
- package/examples/README.md +78 -78
- package/examples/sample_config.json +32 -32
- package/package.json +50 -48
- package/scriptDoc.txt +8679 -8679
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* sessionManager.ts
|
|
4
|
+
* Manages a persistent CODESYS session for improved performance
|
|
5
|
+
*
|
|
6
|
+
* This module implements a session management system that allows
|
|
7
|
+
* keeping a CODESYS instance running for multiple operations, rather
|
|
8
|
+
* than starting and stopping CODESYS for each command.
|
|
9
|
+
*/
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
22
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
23
|
+
}) : function(o, v) {
|
|
24
|
+
o["default"] = v;
|
|
25
|
+
});
|
|
26
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
27
|
+
var ownKeys = function(o) {
|
|
28
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
29
|
+
var ar = [];
|
|
30
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
31
|
+
return ar;
|
|
32
|
+
};
|
|
33
|
+
return ownKeys(o);
|
|
34
|
+
};
|
|
35
|
+
return function (mod) {
|
|
36
|
+
if (mod && mod.__esModule) return mod;
|
|
37
|
+
var result = {};
|
|
38
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
39
|
+
__setModuleDefault(result, mod);
|
|
40
|
+
return result;
|
|
41
|
+
};
|
|
42
|
+
})();
|
|
43
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
44
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
45
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
46
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
47
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
48
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
49
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
53
|
+
exports.CodesysSessionManager = exports.SessionState = exports.SESSION_EVENTS = void 0;
|
|
54
|
+
const child_process_1 = require("child_process");
|
|
55
|
+
const promises_1 = require("fs/promises");
|
|
56
|
+
const path = __importStar(require("path"));
|
|
57
|
+
const os = __importStar(require("os"));
|
|
58
|
+
const fs = __importStar(require("fs"));
|
|
59
|
+
const events_1 = require("events");
|
|
60
|
+
const uuid_1 = require("uuid");
|
|
61
|
+
// Default timeout values
|
|
62
|
+
const DEFAULT_SCRIPT_TIMEOUT = 60000; // 60 seconds
|
|
63
|
+
const DEFAULT_SESSION_IDLE_TIMEOUT = 300000; // 5 minutes
|
|
64
|
+
// Event names
|
|
65
|
+
exports.SESSION_EVENTS = {
|
|
66
|
+
STARTED: 'session:started',
|
|
67
|
+
FAILED: 'session:failed',
|
|
68
|
+
STOPPED: 'session:stopped',
|
|
69
|
+
TIMEOUT: 'session:timeout',
|
|
70
|
+
SCRIPT_COMPLETE: 'script:complete',
|
|
71
|
+
SCRIPT_ERROR: 'script:error'
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Session state constants
|
|
75
|
+
*/
|
|
76
|
+
exports.SessionState = {
|
|
77
|
+
IDLE: 'idle',
|
|
78
|
+
STARTING: 'starting',
|
|
79
|
+
RUNNING: 'running',
|
|
80
|
+
BUSY: 'busy',
|
|
81
|
+
STOPPING: 'stopping',
|
|
82
|
+
STOPPED: 'stopped',
|
|
83
|
+
ERROR: 'error'
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Class to manage a persistent CODESYS session
|
|
87
|
+
*/
|
|
88
|
+
class CodesysSessionManager extends events_1.EventEmitter {
|
|
89
|
+
/**
|
|
90
|
+
* Creates a new CODESYS session manager
|
|
91
|
+
*
|
|
92
|
+
* @param codesysExePath Path to CODESYS.exe
|
|
93
|
+
* @param codesysProfileName CODESYS profile name
|
|
94
|
+
* @param idleTimeoutMs Optional idle timeout in milliseconds
|
|
95
|
+
*/
|
|
96
|
+
constructor(codesysExePath, codesysProfileName, idleTimeoutMs = DEFAULT_SESSION_IDLE_TIMEOUT) {
|
|
97
|
+
super();
|
|
98
|
+
this.codesysProcess = null;
|
|
99
|
+
this.sessionState = exports.SessionState.STOPPED;
|
|
100
|
+
this.idleTimeout = null;
|
|
101
|
+
this.pendingScripts = new Map();
|
|
102
|
+
if (!codesysExePath)
|
|
103
|
+
throw new Error('CODESYS executable path was not provided.');
|
|
104
|
+
if (!codesysProfileName)
|
|
105
|
+
throw new Error('CODESYS profile name was not provided.');
|
|
106
|
+
if (!fs.existsSync(codesysExePath)) {
|
|
107
|
+
throw new Error(`CODESYS executable not found at provided path: ${codesysExePath}`);
|
|
108
|
+
}
|
|
109
|
+
this.codesysExePath = codesysExePath;
|
|
110
|
+
this.codesysProfileName = codesysProfileName;
|
|
111
|
+
this.idleTimeoutMs = idleTimeoutMs;
|
|
112
|
+
// Log status changes through event emitter
|
|
113
|
+
this.on(exports.SESSION_EVENTS.STARTED, () => {
|
|
114
|
+
console.error(`SESSION_MANAGER: Session started successfully`);
|
|
115
|
+
this.sessionState = exports.SessionState.RUNNING;
|
|
116
|
+
this.resetIdleTimeout();
|
|
117
|
+
});
|
|
118
|
+
this.on(exports.SESSION_EVENTS.FAILED, (error) => {
|
|
119
|
+
console.error(`SESSION_MANAGER: Session failed to start: ${error.message}`);
|
|
120
|
+
this.sessionState = exports.SessionState.ERROR;
|
|
121
|
+
});
|
|
122
|
+
this.on(exports.SESSION_EVENTS.STOPPED, () => {
|
|
123
|
+
console.error(`SESSION_MANAGER: Session stopped`);
|
|
124
|
+
this.sessionState = exports.SessionState.STOPPED;
|
|
125
|
+
});
|
|
126
|
+
this.on(exports.SESSION_EVENTS.TIMEOUT, () => {
|
|
127
|
+
console.error(`SESSION_MANAGER: Session timed out due to inactivity`);
|
|
128
|
+
this.stopSession();
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Get current session state
|
|
133
|
+
*/
|
|
134
|
+
getState() {
|
|
135
|
+
return this.sessionState;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Start a CODESYS session
|
|
139
|
+
* @returns Promise that resolves when the session is started
|
|
140
|
+
*/
|
|
141
|
+
startSession() {
|
|
142
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
143
|
+
if (this.sessionState !== exports.SessionState.STOPPED && this.sessionState !== exports.SessionState.ERROR) {
|
|
144
|
+
console.error(`SESSION_MANAGER: Cannot start session - already in state: ${this.sessionState}`);
|
|
145
|
+
return Promise.resolve(); // Session already running
|
|
146
|
+
}
|
|
147
|
+
this.sessionState = exports.SessionState.STARTING;
|
|
148
|
+
return new Promise((resolve, reject) => {
|
|
149
|
+
try {
|
|
150
|
+
console.error(`SESSION_MANAGER: Starting CODESYS session with profile: ${this.codesysProfileName}`);
|
|
151
|
+
// Create a keep-alive script that keeps CODESYS running
|
|
152
|
+
const keepAliveScript = this.createKeepAliveScript();
|
|
153
|
+
// Prepare CODESYS process
|
|
154
|
+
const codesysDir = path.dirname(this.codesysExePath);
|
|
155
|
+
const quotedExePath = `"${this.codesysExePath}"`;
|
|
156
|
+
const profileArg = `--profile="${this.codesysProfileName}"`;
|
|
157
|
+
// Start CODESYS with the keep-alive script - in "visible" mode so we can see it's running
|
|
158
|
+
const fullCommandString = `${quotedExePath} ${profileArg} --runscript="${keepAliveScript}"`;
|
|
159
|
+
// Create a modified environment with CODESYS bin dir in PATH
|
|
160
|
+
const spawnEnv = Object.assign({}, process.env);
|
|
161
|
+
const pathSeparator = os.platform() === 'win32' ? ';' : ':';
|
|
162
|
+
const originalPath = spawnEnv.PATH || '';
|
|
163
|
+
spawnEnv.PATH = `${codesysDir}${pathSeparator}${originalPath}`;
|
|
164
|
+
// Spawn the process
|
|
165
|
+
this.codesysProcess = (0, child_process_1.spawn)(fullCommandString, [], {
|
|
166
|
+
windowsHide: false, // Make visible to user
|
|
167
|
+
cwd: codesysDir,
|
|
168
|
+
env: spawnEnv,
|
|
169
|
+
shell: true
|
|
170
|
+
});
|
|
171
|
+
// Handle process events
|
|
172
|
+
this.codesysProcess.on('error', (error) => {
|
|
173
|
+
console.error(`SESSION_MANAGER: Error starting CODESYS: ${error.message}`);
|
|
174
|
+
this.emit(exports.SESSION_EVENTS.FAILED, error);
|
|
175
|
+
reject(error);
|
|
176
|
+
});
|
|
177
|
+
// Give it a small delay to start properly
|
|
178
|
+
setTimeout(() => {
|
|
179
|
+
if (this.codesysProcess && !this.codesysProcess.killed) {
|
|
180
|
+
this.emit(exports.SESSION_EVENTS.STARTED);
|
|
181
|
+
this.resetIdleTimeout();
|
|
182
|
+
resolve();
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
const error = new Error('CODESYS process failed to start');
|
|
186
|
+
this.emit(exports.SESSION_EVENTS.FAILED, error);
|
|
187
|
+
reject(error);
|
|
188
|
+
}
|
|
189
|
+
}, 2000); // 2 second delay to let CODESYS initialize
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
console.error(`SESSION_MANAGER: Error during session start: ${error.message}`);
|
|
193
|
+
this.emit(exports.SESSION_EVENTS.FAILED, error);
|
|
194
|
+
reject(error);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Stop the CODESYS session
|
|
201
|
+
*/
|
|
202
|
+
stopSession() {
|
|
203
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
204
|
+
if (this.sessionState === exports.SessionState.STOPPED) {
|
|
205
|
+
console.error('SESSION_MANAGER: Session already stopped');
|
|
206
|
+
return Promise.resolve();
|
|
207
|
+
}
|
|
208
|
+
this.sessionState = exports.SessionState.STOPPING;
|
|
209
|
+
// Clear idle timeout if it exists
|
|
210
|
+
if (this.idleTimeout) {
|
|
211
|
+
clearTimeout(this.idleTimeout);
|
|
212
|
+
this.idleTimeout = null;
|
|
213
|
+
}
|
|
214
|
+
// Reject any pending scripts
|
|
215
|
+
for (const [id, pending] of this.pendingScripts.entries()) {
|
|
216
|
+
clearTimeout(pending.timeout);
|
|
217
|
+
pending.reject(new Error('Session was stopped while script was pending'));
|
|
218
|
+
this.pendingScripts.delete(id);
|
|
219
|
+
}
|
|
220
|
+
return new Promise((resolve) => {
|
|
221
|
+
if (this.codesysProcess && !this.codesysProcess.killed) {
|
|
222
|
+
console.error('SESSION_MANAGER: Stopping CODESYS process');
|
|
223
|
+
// First try SIGTERM
|
|
224
|
+
this.codesysProcess.kill('SIGTERM');
|
|
225
|
+
// Set a timeout to force kill if needed
|
|
226
|
+
setTimeout(() => {
|
|
227
|
+
if (this.codesysProcess && !this.codesysProcess.killed) {
|
|
228
|
+
console.error('SESSION_MANAGER: SIGTERM failed, using SIGKILL');
|
|
229
|
+
this.codesysProcess.kill('SIGKILL');
|
|
230
|
+
}
|
|
231
|
+
this.codesysProcess = null;
|
|
232
|
+
this.emit(exports.SESSION_EVENTS.STOPPED);
|
|
233
|
+
resolve();
|
|
234
|
+
}, 2000); // Give it 2 seconds to terminate gracefully
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
this.codesysProcess = null;
|
|
238
|
+
this.emit(exports.SESSION_EVENTS.STOPPED);
|
|
239
|
+
resolve();
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Execute a script in the persistent CODESYS session
|
|
246
|
+
*
|
|
247
|
+
* @param scriptContent The Python script to execute
|
|
248
|
+
* @param timeoutMs Optional timeout for the script execution
|
|
249
|
+
* @returns Promise with script execution result
|
|
250
|
+
*/
|
|
251
|
+
executeScript(scriptContent_1) {
|
|
252
|
+
return __awaiter(this, arguments, void 0, function* (scriptContent, timeoutMs = DEFAULT_SCRIPT_TIMEOUT) {
|
|
253
|
+
// Generate a unique ID for this script execution
|
|
254
|
+
const scriptId = (0, uuid_1.v4)();
|
|
255
|
+
// Make sure we have an active session
|
|
256
|
+
const isActiveSession = this.sessionState === exports.SessionState.RUNNING ||
|
|
257
|
+
this.sessionState === exports.SessionState.BUSY;
|
|
258
|
+
if (!isActiveSession) {
|
|
259
|
+
if (this.sessionState === exports.SessionState.STARTING) {
|
|
260
|
+
// Wait for session to start
|
|
261
|
+
console.error('SESSION_MANAGER: Waiting for session to complete starting');
|
|
262
|
+
yield new Promise((resolve) => {
|
|
263
|
+
const checkInterval = setInterval(() => {
|
|
264
|
+
if (this.sessionState === exports.SessionState.RUNNING ||
|
|
265
|
+
this.sessionState === exports.SessionState.ERROR ||
|
|
266
|
+
this.sessionState === exports.SessionState.STOPPED) {
|
|
267
|
+
clearInterval(checkInterval);
|
|
268
|
+
resolve();
|
|
269
|
+
}
|
|
270
|
+
}, 200);
|
|
271
|
+
});
|
|
272
|
+
const isNowActive = this.sessionState === exports.SessionState.RUNNING ||
|
|
273
|
+
this.sessionState === exports.SessionState.BUSY;
|
|
274
|
+
if (!isNowActive) {
|
|
275
|
+
throw new Error(`Session is in ${this.sessionState} state, not running. Cannot execute script.`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
throw new Error(`Session is in ${this.sessionState} state, not running. Cannot execute script.`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
// Reset idle timeout since we're about to do work
|
|
283
|
+
this.resetIdleTimeout();
|
|
284
|
+
// Mark the session as busy
|
|
285
|
+
this.sessionState = exports.SessionState.BUSY;
|
|
286
|
+
// Return a promise that will be resolved when script execution completes
|
|
287
|
+
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
288
|
+
try {
|
|
289
|
+
// Create a temp file for the script
|
|
290
|
+
const tempDir = os.tmpdir();
|
|
291
|
+
const tempFileName = `codesys_script_${Date.now()}_${Math.random().toString(36).substring(2, 9)}.py`;
|
|
292
|
+
const tempFilePath = path.join(tempDir, tempFileName);
|
|
293
|
+
// Write the script to the temp file
|
|
294
|
+
yield (0, promises_1.writeFile)(tempFilePath, scriptContent, 'latin1');
|
|
295
|
+
console.error(`SESSION_MANAGER: Script ${scriptId} created at ${tempFilePath}`);
|
|
296
|
+
// Set up a timeout for this script execution
|
|
297
|
+
const scriptTimeout = setTimeout(() => {
|
|
298
|
+
if (this.pendingScripts.has(scriptId)) {
|
|
299
|
+
const pending = this.pendingScripts.get(scriptId);
|
|
300
|
+
this.pendingScripts.delete(scriptId);
|
|
301
|
+
pending.reject(new Error(`Script execution timed out after ${timeoutMs}ms`));
|
|
302
|
+
}
|
|
303
|
+
}, timeoutMs);
|
|
304
|
+
// Add to pending scripts
|
|
305
|
+
this.pendingScripts.set(scriptId, {
|
|
306
|
+
resolve: (result) => {
|
|
307
|
+
// Clean up the temp file
|
|
308
|
+
(0, promises_1.unlink)(tempFilePath).catch(err => {
|
|
309
|
+
console.error(`SESSION_MANAGER: Error deleting temp file ${tempFilePath}: ${err.message}`);
|
|
310
|
+
});
|
|
311
|
+
resolve(result);
|
|
312
|
+
// Check if we have more pending scripts
|
|
313
|
+
if (this.pendingScripts.size === 0) {
|
|
314
|
+
this.sessionState = exports.SessionState.RUNNING;
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
reject: (error) => {
|
|
318
|
+
// Clean up the temp file
|
|
319
|
+
(0, promises_1.unlink)(tempFilePath).catch(err => {
|
|
320
|
+
console.error(`SESSION_MANAGER: Error deleting temp file ${tempFilePath}: ${err.message}`);
|
|
321
|
+
});
|
|
322
|
+
reject(error);
|
|
323
|
+
// Check if we have more pending scripts
|
|
324
|
+
if (this.pendingScripts.size === 0) {
|
|
325
|
+
this.sessionState = exports.SessionState.RUNNING;
|
|
326
|
+
}
|
|
327
|
+
},
|
|
328
|
+
timeout: scriptTimeout
|
|
329
|
+
});
|
|
330
|
+
// TODO: Implement the actual execution of the script in the running CODESYS instance
|
|
331
|
+
// For now, we'll just simulate it with a timeout
|
|
332
|
+
setTimeout(() => {
|
|
333
|
+
if (this.pendingScripts.has(scriptId)) {
|
|
334
|
+
const pending = this.pendingScripts.get(scriptId);
|
|
335
|
+
clearTimeout(pending.timeout);
|
|
336
|
+
this.pendingScripts.delete(scriptId);
|
|
337
|
+
// Return a mocked result
|
|
338
|
+
const result = {
|
|
339
|
+
id: scriptId,
|
|
340
|
+
success: true,
|
|
341
|
+
output: "SCRIPT_SUCCESS: This is a mock implementation of script execution!"
|
|
342
|
+
};
|
|
343
|
+
pending.resolve(result);
|
|
344
|
+
}
|
|
345
|
+
}, 1000); // 1 second delay for mock result
|
|
346
|
+
}
|
|
347
|
+
catch (error) {
|
|
348
|
+
reject(error);
|
|
349
|
+
// Check if we have more pending scripts
|
|
350
|
+
if (this.pendingScripts.size === 0) {
|
|
351
|
+
this.sessionState = exports.SessionState.RUNNING;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}));
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Reset the idle timeout
|
|
359
|
+
*/
|
|
360
|
+
resetIdleTimeout() {
|
|
361
|
+
// Clear existing timeout if any
|
|
362
|
+
if (this.idleTimeout) {
|
|
363
|
+
clearTimeout(this.idleTimeout);
|
|
364
|
+
this.idleTimeout = null;
|
|
365
|
+
}
|
|
366
|
+
// Set new timeout
|
|
367
|
+
if (this.idleTimeoutMs > 0) {
|
|
368
|
+
this.idleTimeout = setTimeout(() => {
|
|
369
|
+
console.error(`SESSION_MANAGER: Idle timeout (${this.idleTimeoutMs}ms) reached`);
|
|
370
|
+
this.emit(exports.SESSION_EVENTS.TIMEOUT);
|
|
371
|
+
}, this.idleTimeoutMs);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Create a keep-alive script that keeps CODESYS running
|
|
376
|
+
* This is a placeholder for now - we'll need to implement
|
|
377
|
+
* a proper mechanism to keep CODESYS running while allowing
|
|
378
|
+
* additional scripts to be executed
|
|
379
|
+
*/
|
|
380
|
+
createKeepAliveScript() {
|
|
381
|
+
// This is a placeholder - we need a real implementation
|
|
382
|
+
// that keeps CODESYS running and allows for executing other scripts
|
|
383
|
+
const tempScript = `
|
|
384
|
+
import time
|
|
385
|
+
|
|
386
|
+
# This is a placeholder keep-alive script
|
|
387
|
+
# In a real implementation, we would:
|
|
388
|
+
# 1. Set up a communication channel (named pipe, socket, etc.)
|
|
389
|
+
# 2. Listen for script execution requests
|
|
390
|
+
# 3. Execute them and return results
|
|
391
|
+
|
|
392
|
+
print("Keep-alive script running...")
|
|
393
|
+
|
|
394
|
+
# Just keep running for now
|
|
395
|
+
while True:
|
|
396
|
+
time.sleep(1)
|
|
397
|
+
`;
|
|
398
|
+
return tempScript;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
exports.CodesysSessionManager = CodesysSessionManager;
|
package/docs/index.md
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
# CODESYS MCP Toolkit Documentation
|
|
2
|
-
|
|
3
|
-
Welcome to the documentation for the CODESYS MCP Toolkit!
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
The CODESYS MCP Toolkit provides a bridge between Model Context Protocol (MCP) clients and CODESYS V3 programming environments. This toolkit enables seamless interaction for automating project management, POU creation, code editing, and compilation tasks.
|
|
8
|
-
|
|
9
|
-
## Components
|
|
10
|
-
|
|
11
|
-
- **MCP Server**: Core component that handles MCP protocol communication
|
|
12
|
-
- **CODESYS Script Integration**: Interface with CODESYS scripting engine
|
|
13
|
-
- **Command-Line Interface**: For direct usage and configuration
|
|
14
|
-
|
|
15
|
-
## Getting Started
|
|
16
|
-
|
|
17
|
-
- [Installation](installation.md)
|
|
18
|
-
- [Configuration](configuration.md)
|
|
19
|
-
- [Usage Examples](examples.md)
|
|
20
|
-
- [API Reference](api.md)
|
|
21
|
-
|
|
22
|
-
## Advanced Topics
|
|
23
|
-
|
|
24
|
-
- [Contributing Guidelines](../CONTRIBUTING.md)
|
|
25
|
-
- [Troubleshooting](troubleshooting.md)
|
|
26
|
-
- [Custom Extensions](extensions.md)
|
|
1
|
+
# CODESYS MCP Toolkit Documentation
|
|
2
|
+
|
|
3
|
+
Welcome to the documentation for the CODESYS MCP Toolkit!
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The CODESYS MCP Toolkit provides a bridge between Model Context Protocol (MCP) clients and CODESYS V3 programming environments. This toolkit enables seamless interaction for automating project management, POU creation, code editing, and compilation tasks.
|
|
8
|
+
|
|
9
|
+
## Components
|
|
10
|
+
|
|
11
|
+
- **MCP Server**: Core component that handles MCP protocol communication
|
|
12
|
+
- **CODESYS Script Integration**: Interface with CODESYS scripting engine
|
|
13
|
+
- **Command-Line Interface**: For direct usage and configuration
|
|
14
|
+
|
|
15
|
+
## Getting Started
|
|
16
|
+
|
|
17
|
+
- [Installation](installation.md)
|
|
18
|
+
- [Configuration](configuration.md)
|
|
19
|
+
- [Usage Examples](examples.md)
|
|
20
|
+
- [API Reference](api.md)
|
|
21
|
+
|
|
22
|
+
## Advanced Topics
|
|
23
|
+
|
|
24
|
+
- [Contributing Guidelines](../CONTRIBUTING.md)
|
|
25
|
+
- [Troubleshooting](troubleshooting.md)
|
|
26
|
+
- [Custom Extensions](extensions.md)
|
package/docs/installation.md
CHANGED
|
@@ -1,84 +1,84 @@
|
|
|
1
|
-
# Installation Guide
|
|
2
|
-
|
|
3
|
-
This guide covers how to install the CODESYS MCP Toolkit on your system.
|
|
4
|
-
|
|
5
|
-
## Prerequisites
|
|
6
|
-
|
|
7
|
-
Before installing, ensure you have:
|
|
8
|
-
|
|
9
|
-
1. **Node.js**: Version 18 or later
|
|
10
|
-
- Download from [nodejs.org](https://nodejs.org/)
|
|
11
|
-
- Verify installation with `node --version`
|
|
12
|
-
|
|
13
|
-
2. **CODESYS V3**: A working CODESYS V3 installation
|
|
14
|
-
- Tested with version 3.5 SP21
|
|
15
|
-
- Must have the **Scripting Engine** component enabled
|
|
16
|
-
- Verify by opening CODESYS and checking if scripting commands are available
|
|
17
|
-
|
|
18
|
-
3. **MCP Client**: An MCP-enabled application (e.g., Claude Desktop)
|
|
19
|
-
|
|
20
|
-
## Installation Methods
|
|
21
|
-
|
|
22
|
-
### Method 1: Install from npm (Recommended)
|
|
23
|
-
|
|
24
|
-
The simplest way to install is directly from npm:
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
npm install -g @codesys/mcp-toolkit
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
This installs the package globally on your system, making the `codesys-mcp-toolkit` command available in your terminal.
|
|
31
|
-
|
|
32
|
-
Verify the installation by running:
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
codesys-mcp-toolkit --version
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
### Method 2: Install from Source
|
|
39
|
-
|
|
40
|
-
For development or to get the latest unreleased changes:
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
# Clone the repository
|
|
44
|
-
git clone https://github.com/yourusername/codesys-mcp-toolkit.git
|
|
45
|
-
cd codesys-mcp-toolkit
|
|
46
|
-
|
|
47
|
-
# Install dependencies
|
|
48
|
-
npm install
|
|
49
|
-
|
|
50
|
-
# Build the project
|
|
51
|
-
npm run build
|
|
52
|
-
|
|
53
|
-
# Install globally
|
|
54
|
-
npm install -g .
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
Verify the installation using the same command as above.
|
|
58
|
-
|
|
59
|
-
## Next Steps
|
|
60
|
-
|
|
61
|
-
After installation:
|
|
62
|
-
|
|
63
|
-
1. [Configure your MCP client](configuration.md) to use the CODESYS MCP Toolkit
|
|
64
|
-
2. Try some [basic examples](examples.md)
|
|
65
|
-
3. Learn about the [available tools and resources](api.md)
|
|
66
|
-
|
|
67
|
-
## Troubleshooting Installation Issues
|
|
68
|
-
|
|
69
|
-
### Common Issues
|
|
70
|
-
|
|
71
|
-
- **Permission errors**: You may need to run npm with administrative privileges
|
|
72
|
-
```bash
|
|
73
|
-
sudo npm install -g @codesys/mcp-toolkit # On Linux/macOS
|
|
74
|
-
# or use PowerShell as Administrator on Windows
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
- **Path issues**: Ensure the npm global bin directory is in your PATH
|
|
78
|
-
|
|
79
|
-
- **Node.js version**: Verify you have Node.js 18 or later
|
|
80
|
-
```bash
|
|
81
|
-
node --version
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
If you encounter other issues, please check the [troubleshooting guide](troubleshooting.md) or [open an issue](https://github.com/yourusername/codesys-mcp-toolkit/issues) on GitHub.
|
|
1
|
+
# Installation Guide
|
|
2
|
+
|
|
3
|
+
This guide covers how to install the CODESYS MCP Toolkit on your system.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
Before installing, ensure you have:
|
|
8
|
+
|
|
9
|
+
1. **Node.js**: Version 18 or later
|
|
10
|
+
- Download from [nodejs.org](https://nodejs.org/)
|
|
11
|
+
- Verify installation with `node --version`
|
|
12
|
+
|
|
13
|
+
2. **CODESYS V3**: A working CODESYS V3 installation
|
|
14
|
+
- Tested with version 3.5 SP21
|
|
15
|
+
- Must have the **Scripting Engine** component enabled
|
|
16
|
+
- Verify by opening CODESYS and checking if scripting commands are available
|
|
17
|
+
|
|
18
|
+
3. **MCP Client**: An MCP-enabled application (e.g., Claude Desktop)
|
|
19
|
+
|
|
20
|
+
## Installation Methods
|
|
21
|
+
|
|
22
|
+
### Method 1: Install from npm (Recommended)
|
|
23
|
+
|
|
24
|
+
The simplest way to install is directly from npm:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install -g @codesys/mcp-toolkit
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
This installs the package globally on your system, making the `codesys-mcp-toolkit` command available in your terminal.
|
|
31
|
+
|
|
32
|
+
Verify the installation by running:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
codesys-mcp-toolkit --version
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Method 2: Install from Source
|
|
39
|
+
|
|
40
|
+
For development or to get the latest unreleased changes:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Clone the repository
|
|
44
|
+
git clone https://github.com/yourusername/codesys-mcp-toolkit.git
|
|
45
|
+
cd codesys-mcp-toolkit
|
|
46
|
+
|
|
47
|
+
# Install dependencies
|
|
48
|
+
npm install
|
|
49
|
+
|
|
50
|
+
# Build the project
|
|
51
|
+
npm run build
|
|
52
|
+
|
|
53
|
+
# Install globally
|
|
54
|
+
npm install -g .
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Verify the installation using the same command as above.
|
|
58
|
+
|
|
59
|
+
## Next Steps
|
|
60
|
+
|
|
61
|
+
After installation:
|
|
62
|
+
|
|
63
|
+
1. [Configure your MCP client](configuration.md) to use the CODESYS MCP Toolkit
|
|
64
|
+
2. Try some [basic examples](examples.md)
|
|
65
|
+
3. Learn about the [available tools and resources](api.md)
|
|
66
|
+
|
|
67
|
+
## Troubleshooting Installation Issues
|
|
68
|
+
|
|
69
|
+
### Common Issues
|
|
70
|
+
|
|
71
|
+
- **Permission errors**: You may need to run npm with administrative privileges
|
|
72
|
+
```bash
|
|
73
|
+
sudo npm install -g @codesys/mcp-toolkit # On Linux/macOS
|
|
74
|
+
# or use PowerShell as Administrator on Windows
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
- **Path issues**: Ensure the npm global bin directory is in your PATH
|
|
78
|
+
|
|
79
|
+
- **Node.js version**: Verify you have Node.js 18 or later
|
|
80
|
+
```bash
|
|
81
|
+
node --version
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
If you encounter other issues, please check the [troubleshooting guide](troubleshooting.md) or [open an issue](https://github.com/yourusername/codesys-mcp-toolkit/issues) on GitHub.
|