@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.
@@ -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)
@@ -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.