@codesys/mcp-toolkit 1.0.1 → 1.0.4
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/CHANGELOG.md +26 -26
- package/CONTRIBUTING.md +72 -72
- package/LICENSE +21 -21
- package/README.md +254 -254
- package/README.md.enhanced +155 -155
- package/dist/codesys_interop.js +55 -44
- package/dist/server.js +879 -879
- package/docs/configuration.md +119 -119
- package/docs/index.md +26 -26
- package/docs/installation.md +84 -84
- package/examples/README.md +78 -78
- package/examples/sample_config.json +32 -32
- package/package.json +47 -47
- package/dist/codesys_interop - Copy.js +0 -180
- package/dist/server - Copy.js +0 -1444
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
{
|
|
2
|
-
"mcpServers": {
|
|
3
|
-
"codesys_local": {
|
|
4
|
-
"command": "npx",
|
|
5
|
-
"args": [
|
|
6
|
-
"-y",
|
|
7
|
-
"@codesys/mcp-toolkit",
|
|
8
|
-
"--codesys-path", "C:\\Program Files\\CODESYS 3.5.21.0\\CODESYS\\Common\\CODESYS.exe",
|
|
9
|
-
"--codesys-profile", "CODESYS V3.5 SP21"
|
|
10
|
-
]
|
|
11
|
-
},
|
|
12
|
-
"filesystem": {
|
|
13
|
-
"command": "npx",
|
|
14
|
-
"args": [
|
|
15
|
-
"-y",
|
|
16
|
-
"@modelcontextprotocol/server-filesystem",
|
|
17
|
-
"C:/MyProjects"
|
|
18
|
-
]
|
|
19
|
-
},
|
|
20
|
-
"memory": {
|
|
21
|
-
"command": "npx",
|
|
22
|
-
"args": [
|
|
23
|
-
"-y",
|
|
24
|
-
"@modelcontextprotocol/server-memory"
|
|
25
|
-
]
|
|
26
|
-
},
|
|
27
|
-
"puppeteer": {
|
|
28
|
-
"command": "npx",
|
|
29
|
-
"args": ["-y", "@modelcontextprotocol/server-puppeteer"]
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"mcpServers": {
|
|
3
|
+
"codesys_local": {
|
|
4
|
+
"command": "npx",
|
|
5
|
+
"args": [
|
|
6
|
+
"-y",
|
|
7
|
+
"@codesys/mcp-toolkit",
|
|
8
|
+
"--codesys-path", "C:\\Program Files\\CODESYS 3.5.21.0\\CODESYS\\Common\\CODESYS.exe",
|
|
9
|
+
"--codesys-profile", "CODESYS V3.5 SP21"
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
"filesystem": {
|
|
13
|
+
"command": "npx",
|
|
14
|
+
"args": [
|
|
15
|
+
"-y",
|
|
16
|
+
"@modelcontextprotocol/server-filesystem",
|
|
17
|
+
"C:/MyProjects"
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
"memory": {
|
|
21
|
+
"command": "npx",
|
|
22
|
+
"args": [
|
|
23
|
+
"-y",
|
|
24
|
+
"@modelcontextprotocol/server-memory"
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
"puppeteer": {
|
|
28
|
+
"command": "npx",
|
|
29
|
+
"args": ["-y", "@modelcontextprotocol/server-puppeteer"]
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
package/package.json
CHANGED
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@codesys/mcp-toolkit",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"main": "dist/server.js",
|
|
5
|
-
"bin": {
|
|
6
|
-
"codesys-mcp-toolkit": "./dist/bin.js"
|
|
7
|
-
},
|
|
8
|
-
"scripts": {
|
|
9
|
-
"test": "echo \"Error: no test specified\" && exit 1",
|
|
10
|
-
"build": "tsc",
|
|
11
|
-
"prepare": "npm run build"
|
|
12
|
-
},
|
|
13
|
-
"keywords": [
|
|
14
|
-
"codesys",
|
|
15
|
-
"mcp",
|
|
16
|
-
"modelcontextprotocol",
|
|
17
|
-
"plc",
|
|
18
|
-
"automation",
|
|
19
|
-
"programming"
|
|
20
|
-
],
|
|
21
|
-
"author": "Your Name <your.email@example.com>",
|
|
22
|
-
"license": "MIT",
|
|
23
|
-
"type": "commonjs",
|
|
24
|
-
"description": "Model Context Protocol (MCP) server for CODESYS automation platform",
|
|
25
|
-
"repository": {
|
|
26
|
-
"type": "git",
|
|
27
|
-
"url": "git+https://github.com/johannesPettersson80/codesys-mcp-toolkit.git"
|
|
28
|
-
},
|
|
29
|
-
"homepage": "https://github.com/johannesPettersson80/codesys-mcp-toolkit#readme",
|
|
30
|
-
"bugs": {
|
|
31
|
-
"url": "https://github.com/johannesPettersson80/codesys-mcp-toolkit/issues"
|
|
32
|
-
},
|
|
33
|
-
"engines": {
|
|
34
|
-
"node": ">=14.0.0"
|
|
35
|
-
},
|
|
36
|
-
"dependencies": {
|
|
37
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
38
|
-
"axios": "^1.6.8",
|
|
39
|
-
"commander": "^11.1.0",
|
|
40
|
-
"zod": "^3.24.
|
|
41
|
-
},
|
|
42
|
-
"devDependencies": {
|
|
43
|
-
"@types/commander": "^2.12.5",
|
|
44
|
-
"@types/node": "^22.14.1",
|
|
45
|
-
"typescript": "^5.8.3"
|
|
46
|
-
}
|
|
47
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@codesys/mcp-toolkit",
|
|
3
|
+
"version": "1.0.4",
|
|
4
|
+
"main": "dist/server.js",
|
|
5
|
+
"bin": {
|
|
6
|
+
"codesys-mcp-toolkit": "./dist/bin.js"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"prepare": "npm run build"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"codesys",
|
|
15
|
+
"mcp",
|
|
16
|
+
"modelcontextprotocol",
|
|
17
|
+
"plc",
|
|
18
|
+
"automation",
|
|
19
|
+
"programming"
|
|
20
|
+
],
|
|
21
|
+
"author": "Your Name <your.email@example.com>",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"type": "commonjs",
|
|
24
|
+
"description": "Model Context Protocol (MCP) server for CODESYS automation platform",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/johannesPettersson80/codesys-mcp-toolkit.git"
|
|
28
|
+
},
|
|
29
|
+
"homepage": "https://github.com/johannesPettersson80/codesys-mcp-toolkit#readme",
|
|
30
|
+
"bugs": {
|
|
31
|
+
"url": "https://github.com/johannesPettersson80/codesys-mcp-toolkit/issues"
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=14.0.0"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@modelcontextprotocol/sdk": "^1.10.2",
|
|
38
|
+
"axios": "^1.6.8",
|
|
39
|
+
"commander": "^11.1.0",
|
|
40
|
+
"zod": "^3.24.3"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/commander": "^2.12.5",
|
|
44
|
+
"@types/node": "^22.14.1",
|
|
45
|
+
"typescript": "^5.8.3"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
-
});
|
|
43
|
-
};
|
|
44
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
-
exports.executeCodesysScript = executeCodesysScript;
|
|
46
|
-
const child_process_1 = require("child_process");
|
|
47
|
-
const promises_1 = require("fs/promises");
|
|
48
|
-
const path = __importStar(require("path"));
|
|
49
|
-
const os = __importStar(require("os"));
|
|
50
|
-
// Define expected success/error markers from the Python scripts
|
|
51
|
-
const SCRIPT_SUCCESS_MARKER = 'SCRIPT_SUCCESS';
|
|
52
|
-
const SCRIPT_ERROR_MARKER = 'SCRIPT_ERROR';
|
|
53
|
-
/**
|
|
54
|
-
* Executes a CODESYS Python script using the command line interface.
|
|
55
|
-
*
|
|
56
|
-
* @param scriptContent The Python script code to execute.
|
|
57
|
-
* @param codesysExePath The full path to the CODESYS.exe executable.
|
|
58
|
-
* @param codesysProfileName The name of the CODESYS profile to use for scripting.
|
|
59
|
-
* @returns A promise resolving to an object containing the success status and the script's output.
|
|
60
|
-
*/
|
|
61
|
-
function executeCodesysScript(scriptContent, codesysExePath, codesysProfileName) {
|
|
62
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
63
|
-
// Validate arguments passed to the function
|
|
64
|
-
if (!codesysExePath) {
|
|
65
|
-
throw new Error('CODESYS executable path was not provided to executeCodesysScript.');
|
|
66
|
-
}
|
|
67
|
-
if (!codesysProfileName) {
|
|
68
|
-
throw new Error('CODESYS profile name was not provided to executeCodesysScript.');
|
|
69
|
-
}
|
|
70
|
-
// Create a temporary file for the script
|
|
71
|
-
const tempDir = os.tmpdir();
|
|
72
|
-
const tempFileName = `codesys_script_${Date.now()}_${Math.random().toString(36).substring(7)}.py`;
|
|
73
|
-
const tempFilePath = path.join(tempDir, tempFileName);
|
|
74
|
-
let output = '';
|
|
75
|
-
let success = false;
|
|
76
|
-
try {
|
|
77
|
-
// Normalize line endings to LF (\n)
|
|
78
|
-
const normalizedScriptContent = scriptContent.replace(/\r\n/g, '\n');
|
|
79
|
-
// Write the script content to the temporary file using latin1 encoding
|
|
80
|
-
yield (0, promises_1.writeFile)(tempFilePath, normalizedScriptContent, 'latin1'); // Explicitly use latin1
|
|
81
|
-
process.stderr.write(`Temporary script written to: ${tempFilePath} with latin1 encoding and LF line endings\n`); // Use process.stderr
|
|
82
|
-
// Add --additionalfolder argument
|
|
83
|
-
const additionalFolderPath = "C:\\Program Files\\CODESYS 3.5.21.0\\CODESYS\\AdditionalFolders\\Default"; // Assuming Default instance
|
|
84
|
-
// Fix: Use shell:true and pass the entire command as a single string without additionalfolder
|
|
85
|
-
const commandWithArgs = `"${codesysExePath}" --profile="${codesysProfileName}" --noUI --runscript="${tempFilePath}"`;
|
|
86
|
-
process.stderr.write(`Executing: ${commandWithArgs}\n`); // Log the command string
|
|
87
|
-
// Spawn the CODESYS process using shell:true for proper argument handling
|
|
88
|
-
const codesysProcess = (0, child_process_1.spawn)(commandWithArgs, {
|
|
89
|
-
stdio: ['ignore', 'pipe', 'pipe'], // Ignore stdin, pipe stdout and stderr
|
|
90
|
-
shell: true // Use shell to handle the command string properly
|
|
91
|
-
});
|
|
92
|
-
// Capture stdout
|
|
93
|
-
codesysProcess.stdout.on('data', (data) => {
|
|
94
|
-
const chunk = data.toString();
|
|
95
|
-
// console.error('CODESYS stdout:', chunk); // Optional: Original debug log
|
|
96
|
-
output += chunk;
|
|
97
|
-
});
|
|
98
|
-
// Capture stderr
|
|
99
|
-
codesysProcess.stderr.on('data', (data) => {
|
|
100
|
-
const chunk = data.toString();
|
|
101
|
-
process.stderr.write(`CODESYS stderr: ${chunk}\n`); // Use process.stderr
|
|
102
|
-
output += chunk; // Include stderr in the output for debugging
|
|
103
|
-
});
|
|
104
|
-
// Wait for the process to exit with a timeout
|
|
105
|
-
const exitCode = yield new Promise((resolve, reject) => {
|
|
106
|
-
// Add timeout handling
|
|
107
|
-
const timeoutMs = 30000; // 30 seconds
|
|
108
|
-
const timeout = setTimeout(() => {
|
|
109
|
-
process.stderr.write(`TIMEOUT: CODESYS process did not complete in ${timeoutMs}ms\n`);
|
|
110
|
-
// Force resolve with 0 to proceed with parsing output collected so far
|
|
111
|
-
codesysProcess.kill();
|
|
112
|
-
resolve(0);
|
|
113
|
-
}, timeoutMs);
|
|
114
|
-
codesysProcess.on('close', (code) => {
|
|
115
|
-
clearTimeout(timeout);
|
|
116
|
-
resolve(code !== null && code !== void 0 ? code : 0);
|
|
117
|
-
});
|
|
118
|
-
codesysProcess.on('error', (err) => {
|
|
119
|
-
clearTimeout(timeout);
|
|
120
|
-
// Error starting the process itself (e.g., command not found)
|
|
121
|
-
process.stderr.write(`Failed to start CODESYS process: ${err.message}\n`); // Use process.stderr
|
|
122
|
-
reject(err);
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
process.stderr.write(`CODESYS process exited with code: ${exitCode}\n`); // Use process.stderr
|
|
126
|
-
// Determine success based on exit code and output markers
|
|
127
|
-
// Note: CODESYS scripting might return exit code 0 even if the script had logical errors.
|
|
128
|
-
// Relying on specific output markers is more robust.
|
|
129
|
-
if (output.includes(SCRIPT_SUCCESS_MARKER)) {
|
|
130
|
-
success = true;
|
|
131
|
-
}
|
|
132
|
-
else if (output.includes(SCRIPT_ERROR_MARKER)) {
|
|
133
|
-
success = false;
|
|
134
|
-
}
|
|
135
|
-
else {
|
|
136
|
-
// If no markers found, fall back to exit code (less reliable)
|
|
137
|
-
success = exitCode === 0;
|
|
138
|
-
if (!success) {
|
|
139
|
-
// Append the specific CODESYS error if available and no other marker found
|
|
140
|
-
if (!output.includes(SCRIPT_ERROR_MARKER)) {
|
|
141
|
-
output += `\nSCRIPT_ERROR: Process exited with non-zero code ${exitCode}. Check CODESYS stderr output above for details.`;
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
output += `\nSCRIPT_ERROR: Process exited with non-zero code ${exitCode}.`;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
else {
|
|
148
|
-
// If exit code is 0 but no success marker, treat as potential issue or simple script
|
|
149
|
-
console.error("Warning: CODESYS script finished with exit code 0 but no SCRIPT_SUCCESS marker found."); // Log warning to stderr
|
|
150
|
-
// Optionally, you could treat this as success or failure depending on requirements
|
|
151
|
-
// For now, let's assume success if exit code is 0 and no error marker.
|
|
152
|
-
if (!output.includes(SCRIPT_ERROR_MARKER)) {
|
|
153
|
-
success = true;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
catch (error) {
|
|
159
|
-
process.stderr.write(`Error executing CODESYS script: ${error}\n`); // Use process.stderr
|
|
160
|
-
output += `\nSCRIPT_ERROR: Failed to execute script process. ${error.message}`;
|
|
161
|
-
success = false;
|
|
162
|
-
}
|
|
163
|
-
finally {
|
|
164
|
-
// Clean up the temporary file
|
|
165
|
-
try {
|
|
166
|
-
yield (0, promises_1.unlink)(tempFilePath);
|
|
167
|
-
process.stderr.write(`Temporary script deleted: ${tempFilePath}\n`); // Use process.stderr
|
|
168
|
-
}
|
|
169
|
-
catch (cleanupError) {
|
|
170
|
-
process.stderr.write(`Failed to delete temporary script file ${tempFilePath}: ${cleanupError}\n`); // Use process.stderr
|
|
171
|
-
// Don't overwrite the original error if cleanup fails
|
|
172
|
-
if (success) { // Only add cleanup error if the main process didn't already fail
|
|
173
|
-
output += `\nWARNING: Failed to delete temporary script file ${tempFilePath}. ${cleanupError.message}`;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
process.stderr.write(`Final script output received:\n---\n${output}\n---\n`); // Use process.stderr
|
|
178
|
-
return { success, output }; // Revert return object
|
|
179
|
-
});
|
|
180
|
-
}
|