@codesys/mcp-toolkit 1.5.8 → 2.0.0-alpha.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/CHANGELOG.md +153 -189
- package/LICENSE +21 -21
- package/README.md +224 -107
- package/dist/actions.d.ts +28 -0
- package/dist/actions.js +98 -0
- package/dist/actions.js.map +1 -0
- package/dist/bridge/bridge.d.ts +105 -0
- package/dist/bridge/bridge.js +400 -0
- package/dist/bridge/bridge.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +196 -0
- package/dist/cli.js.map +1 -0
- package/dist/codesys/cache.d.ts +48 -0
- package/dist/codesys/cache.js +82 -0
- package/dist/codesys/cache.js.map +1 -0
- package/dist/codesys/changes.d.ts +57 -0
- package/dist/codesys/changes.js +133 -0
- package/dist/codesys/changes.js.map +1 -0
- package/dist/codesys/decl.d.ts +45 -0
- package/dist/codesys/decl.js +251 -0
- package/dist/codesys/decl.js.map +1 -0
- package/dist/codesys/devices.d.ts +34 -0
- package/dist/codesys/devices.js +82 -0
- package/dist/codesys/devices.js.map +1 -0
- package/dist/codesys/diff.d.ts +13 -0
- package/dist/codesys/diff.js +61 -0
- package/dist/codesys/diff.js.map +1 -0
- package/dist/codesys/install.d.ts +40 -0
- package/dist/codesys/install.js +144 -0
- package/dist/codesys/install.js.map +1 -0
- package/dist/codesys/library-browse.d.ts +19 -0
- package/dist/codesys/library-browse.js +57 -0
- package/dist/codesys/library-browse.js.map +1 -0
- package/dist/codesys/outline.d.ts +32 -0
- package/dist/codesys/outline.js +219 -0
- package/dist/codesys/outline.js.map +1 -0
- package/dist/codesys/simulation.d.ts +34 -0
- package/dist/codesys/simulation.js +57 -0
- package/dist/codesys/simulation.js.map +1 -0
- package/dist/codesys/st.d.ts +36 -0
- package/dist/codesys/st.js +69 -0
- package/dist/codesys/st.js.map +1 -0
- package/dist/daemon.d.ts +46 -0
- package/dist/daemon.js +173 -0
- package/dist/daemon.js.map +1 -0
- package/dist/driver.d.ts +25 -0
- package/dist/driver.js +33 -0
- package/dist/driver.js.map +1 -0
- package/dist/panel/sim-panel.html +357 -0
- package/dist/panel/viewer.html +126 -0
- package/dist/panel-types.d.ts +20 -0
- package/dist/panel-types.js +3 -0
- package/dist/panel-types.js.map +1 -0
- package/dist/panel.d.ts +27 -0
- package/dist/panel.js +208 -0
- package/dist/panel.js.map +1 -0
- package/dist/server.d.ts +5 -0
- package/dist/server.js +33 -974
- package/dist/server.js.map +1 -0
- package/dist/tools.d.ts +103 -0
- package/dist/tools.js +793 -0
- package/dist/tools.js.map +1 -0
- package/dist/viewer.d.ts +14 -0
- package/dist/viewer.js +125 -0
- package/dist/viewer.js.map +1 -0
- package/package.json +37 -21
- package/watcher/mcp_compat.py +147 -0
- package/watcher/mcp_ops.py +1178 -0
- package/watcher/mcp_sim.py +246 -0
- package/watcher/watcher.py +255 -0
- package/.claude/settings.local.json +0 -29
- package/CLAUDE.md +0 -26
- package/CONTRIBUTING.md +0 -72
- package/README.md.enhanced +0 -155
- package/codesys-mcp-toolkit-1.2.0.tgz +0 -0
- package/codesys-mcp-toolkit-1.2.1.tgz +0 -0
- package/codesys-mcp-toolkit-1.5.7.tgz +0 -0
- package/codesys-mcp-toolkit-1.5.8.tgz +0 -0
- package/dist/bin.js +0 -75
- package/dist/check_session_paths.js +0 -149
- package/dist/codesys_interop.js +0 -435
- package/dist/direct_session_command.js +0 -293
- package/dist/scriptLoader.js +0 -165
- package/dist/scripts/check_status.py +0 -21
- package/dist/scripts/compile_project.py +0 -65
- package/dist/scripts/create_method.py +0 -80
- package/dist/scripts/create_pou.py +0 -102
- package/dist/scripts/create_project.py +0 -116
- package/dist/scripts/create_property.py +0 -78
- package/dist/scripts/ensure_project_open.py +0 -154
- package/dist/scripts/find_object_by_path.py +0 -111
- package/dist/scripts/get_pou_code.py +0 -91
- package/dist/scripts/get_project_structure.py +0 -72
- package/dist/scripts/open_project.py +0 -25
- package/dist/scripts/save_project.py +0 -29
- package/dist/scripts/session_status.py +0 -281
- package/dist/scripts/set_pou_code.py +0 -109
- package/dist/scripts/start_session.py +0 -809
- package/dist/scripts/stop_session.py +0 -324
- package/dist/sessionManager.js +0 -798
- package/docs/configuration.md +0 -141
- package/docs/index.md +0 -26
- package/docs/installation.md +0 -84
- package/docs/session_management.md +0 -110
- package/examples/README.md +0 -78
- package/examples/sample_config.json +0 -32
- package/replacements_session_status.txt +0 -16
- package/scriptDoc.txt +0 -8679
- package/scripts/build.js +0 -25
- package/scripts/fix_fstrings.py +0 -76
package/dist/server.js
CHANGED
|
@@ -1,975 +1,34 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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());
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/server";
|
|
2
|
+
import { EXTENSION_ID } from "@modelcontextprotocol/ext-apps/server";
|
|
3
|
+
import { currentCodesysSim } from "./codesys/simulation.js";
|
|
4
|
+
import { registerTools, revertObject, versionLine } from "./tools.js";
|
|
5
|
+
import { registerPanel } from "./panel.js";
|
|
6
|
+
export const VERSION = "2.0.0-alpha.0";
|
|
7
|
+
const INSTRUCTIONS = `CODESYS V3.5 automation through a persistent CODESYS session.
|
|
8
|
+
Everything goes through the one tool named codesys, as {"action": "<name>", "args": {...}}. The names below are its actions; {"action": "help"} lists them all with their arguments.
|
|
9
|
+
Use batch whenever you know the next steps: it sends several actions in one call and is much faster than separate calls. For example, all the create_object and write_object calls of a step followed by compile, or codesys_sim_force, wait, codesys_sim_cycle and codesys_sim_read for one test.
|
|
10
|
+
Workflow: open_project (or create_project) -> get_project_tree -> read_objects -> write_object / create_object -> compile.
|
|
11
|
+
Object paths are relative to the active application: 'PLC_PRG', 'FB_Pump/Start' (method), 'FB_Pump/Speed/Get' (property accessor).
|
|
12
|
+
Only Structured Text is supported; objects with graphical bodies are marked [non-ST] and are read-only.
|
|
13
|
+
The first call after start can take 1-3 minutes while CODESYS starts; codesys_status shows progress without waiting.
|
|
14
|
+
To check that logic works, use CODESYS's own simulation (no controller, nothing extra to install, the real compiler and libraries): codesys_sim_start -> codesys_sim_control (run) or codesys_sim_cycle (exact cycles) -> codesys_sim_read / write / force / unforce -> codesys_sim_stop. The project is locked until codesys_sim_stop.
|
|
15
|
+
Fix code with write_object after codesys_sim_stop, then codesys_sim_start again to load it.
|
|
16
|
+
Right after opening or creating a project, call the separate tool open_sim_panel: it shows the user a live CODESYS-style workspace in the chat (the project tree and the code as you write it, changes, compile results and the simulation), so they can watch you work.`;
|
|
17
|
+
export function createServer(ctx) {
|
|
18
|
+
// A host treats an extension the server doesn't advertise as unsupported, and then runs
|
|
19
|
+
// open_sim_panel as a plain text tool and never fetches the card's page.
|
|
20
|
+
const server = new McpServer({ name: "codesys-mcp-toolkit", version: VERSION }, { instructions: INSTRUCTIONS, capabilities: { extensions: { [EXTENSION_ID]: {} } } });
|
|
21
|
+
registerTools(server, ctx);
|
|
22
|
+
registerPanel(server, {
|
|
23
|
+
cache: ctx.cache,
|
|
24
|
+
changes: ctx.changes,
|
|
25
|
+
project: () => ctx.project?.path,
|
|
26
|
+
versions: () => versionLine(ctx.codesys?.label, ctx.bridge.health().scripting, ctx.project?.compiler_version),
|
|
27
|
+
codesysSim: () => currentCodesysSim(ctx),
|
|
28
|
+
driver: ctx.driver,
|
|
29
|
+
revert: (path, to) => revertObject(ctx, path, to),
|
|
30
|
+
log: (m) => ctx.log?.(m),
|
|
50
31
|
});
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
// --- Import 'os' FIRST ---
|
|
55
|
-
const os = __importStar(require("os"));
|
|
56
|
-
// --- End Import 'os' ---
|
|
57
|
-
// --- STARTUP LOG ---
|
|
58
|
-
console.error(`>>> SERVER.TS TOP LEVEL EXECUTION @ ${new Date().toISOString()} <<<`);
|
|
59
|
-
console.error(`>>> Node: ${process.version}, Platform: ${os.platform()}, Arch: ${os.arch()}`);
|
|
60
|
-
console.error(`>>> Initial CWD: ${process.cwd()}`);
|
|
61
|
-
// --- End Startup Log ---
|
|
62
|
-
// --- Necessary Imports ---
|
|
63
|
-
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
64
|
-
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
65
|
-
const zod_1 = require("zod");
|
|
66
|
-
const codesys_interop_1 = require("./codesys_interop");
|
|
67
|
-
const path = __importStar(require("path"));
|
|
68
|
-
const promises_1 = require("fs/promises");
|
|
69
|
-
const fs = __importStar(require("fs"));
|
|
70
|
-
const scriptLoader_1 = require("./scriptLoader");
|
|
71
|
-
const sessionManager_1 = require("./sessionManager");
|
|
72
|
-
const direct_session_command_1 = require("./direct_session_command");
|
|
73
|
-
// --- Wrap server logic in an exported function ---
|
|
74
|
-
function startMcpServer(config) {
|
|
75
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
76
|
-
console.error(`>>> SERVER.TS startMcpServer() CALLED @ ${new Date().toISOString()} <<<`);
|
|
77
|
-
console.error(`>>> Config Received: ${JSON.stringify(config)}`);
|
|
78
|
-
// --- Use config values directly ---
|
|
79
|
-
const WORKSPACE_DIR = config.workspaceDir;
|
|
80
|
-
const codesysExePath = config.codesysPath;
|
|
81
|
-
const codesysProfileName = config.profileName;
|
|
82
|
-
console.error(`SERVER.TS: Using Workspace Directory: ${WORKSPACE_DIR}`);
|
|
83
|
-
console.error(`SERVER.TS: Using CODESYS Path: ${codesysExePath}`);
|
|
84
|
-
console.error(`SERVER.TS: Using CODESYS Profile: ${codesysProfileName}`);
|
|
85
|
-
// --- Sanity check - confirm the path exists if possible ---
|
|
86
|
-
console.error(`SERVER.TS: Checking existence of CODESYS executable: ${codesysExePath}`);
|
|
87
|
-
try {
|
|
88
|
-
// Using sync check here as it's part of initial setup before async operations start
|
|
89
|
-
const fsChecker = require('fs');
|
|
90
|
-
if (!fsChecker.existsSync(codesysExePath)) {
|
|
91
|
-
console.error(`SERVER.TS ERROR: Determined CODESYS executable path does not exist: ${codesysExePath}`);
|
|
92
|
-
throw new Error(`CODESYS executable not found at specified path: ${codesysExePath}`);
|
|
93
|
-
}
|
|
94
|
-
else {
|
|
95
|
-
console.error(`SERVER.TS: Confirmed CODESYS executable exists.`);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
catch (err) {
|
|
99
|
-
console.error(`SERVER.TS ERROR: Error checking CODESYS path existence: ${err.message}`);
|
|
100
|
-
throw err; // Rethrow the error to be caught by the caller (bin.ts)
|
|
101
|
-
}
|
|
102
|
-
// --- End Configuration Handling ---
|
|
103
|
-
// --- Helper Function (fileExists - async version) ---
|
|
104
|
-
function fileExists(filePath) {
|
|
105
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
106
|
-
try {
|
|
107
|
-
yield (0, promises_1.stat)(filePath);
|
|
108
|
-
return true;
|
|
109
|
-
}
|
|
110
|
-
catch (error) {
|
|
111
|
-
if (error.code === 'ENOENT') {
|
|
112
|
-
return false; // File does not exist
|
|
113
|
-
}
|
|
114
|
-
throw error; // Other error
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
// --- End Helper Function ---
|
|
119
|
-
// --- Initialize Session Manager ---
|
|
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 (will remain undefined if session management is disabled)
|
|
124
|
-
let sessionManager = undefined;
|
|
125
|
-
if (enableSessionManagement) {
|
|
126
|
-
try {
|
|
127
|
-
sessionManager = new sessionManager_1.CodesysSessionManager(codesysExePath, codesysProfileName);
|
|
128
|
-
console.error('SERVER.TS: Session manager initialized');
|
|
129
|
-
// Only start a session if explicitly enabled and manager was created successfully
|
|
130
|
-
if (sessionManager) {
|
|
131
|
-
try {
|
|
132
|
-
// Check if session is already active
|
|
133
|
-
console.error('SERVER.TS: Checking if session is already active...');
|
|
134
|
-
const isActive = (0, direct_session_command_1.isSessionActive)();
|
|
135
|
-
if (isActive) {
|
|
136
|
-
console.error('SERVER.TS: Session is already active');
|
|
137
|
-
}
|
|
138
|
-
else {
|
|
139
|
-
console.error('SERVER.TS: Session not active, starting new session...');
|
|
140
|
-
console.error('SERVER.TS: IMPORTANT: If CODESYS hangs during session startup, use --no-session flag');
|
|
141
|
-
yield sessionManager.startSession();
|
|
142
|
-
console.error('SERVER.TS: Session start initiated');
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
catch (error) {
|
|
146
|
-
console.error(`SERVER.TS: Error starting session: ${error.message}`);
|
|
147
|
-
console.error('SERVER.TS: Will fallback to one-time execution for operations');
|
|
148
|
-
// Continue without session, will fallback to one-time execution
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
console.error('SERVER.TS: Session manager creation failed');
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
catch (error) {
|
|
156
|
-
console.error(`SERVER.TS: Failed to create session manager: ${error.message}`);
|
|
157
|
-
console.error('SERVER.TS: Will fallback to one-time execution for operations');
|
|
158
|
-
sessionManager = undefined;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
else {
|
|
162
|
-
console.error('SERVER.TS: Session management is disabled, will use one-time script execution');
|
|
163
|
-
}
|
|
164
|
-
if (!sessionManager) {
|
|
165
|
-
console.error('SERVER.TS: Session manager is not available - one-time script execution will be used');
|
|
166
|
-
}
|
|
167
|
-
// --- End Session Manager Initialization ---
|
|
168
|
-
// --- Preload script templates ---
|
|
169
|
-
try {
|
|
170
|
-
yield (0, scriptLoader_1.preloadAllScriptTemplates)();
|
|
171
|
-
}
|
|
172
|
-
catch (err) {
|
|
173
|
-
console.error(`SERVER.TS ERROR: Error preloading script templates: ${err.message}`);
|
|
174
|
-
// Continue execution, as script templates will be loaded on demand as needed
|
|
175
|
-
}
|
|
176
|
-
// --- MCP Server Initialization ---
|
|
177
|
-
console.error("SERVER.TS: Initializing McpServer...");
|
|
178
|
-
const server = new mcp_js_1.McpServer({
|
|
179
|
-
name: "CODESYS Control MCP Server",
|
|
180
|
-
version: "1.8.3", // Updated version with null reference fixes for session management
|
|
181
|
-
capabilities: {
|
|
182
|
-
resources: { listChanged: true },
|
|
183
|
-
tools: { listChanged: true }
|
|
184
|
-
}
|
|
185
|
-
});
|
|
186
|
-
console.error("SERVER.TS: McpServer instance created.");
|
|
187
|
-
// --- End MCP Server Initialization ---
|
|
188
|
-
// --- Zod Schemas ---
|
|
189
|
-
const PouTypeEnum = zod_1.z.enum(["Program", "FunctionBlock", "Function"]);
|
|
190
|
-
const ImplementationLanguageEnum = zod_1.z.enum(["ST", "LD", "FBD", "SFC", "IL", "CFC", "StructuredText", "LadderDiagram", "FunctionBlockDiagram", "SequentialFunctionChart", "InstructionList", "ContinuousFunctionChart"]);
|
|
191
|
-
// --- End Zod Schemas ---
|
|
192
|
-
// --- MCP Resources / Tools Definitions ---
|
|
193
|
-
console.error("SERVER.TS: Defining Resources and Tools...");
|
|
194
|
-
// --- Resources ---
|
|
195
|
-
server.resource("project-status", "codesys://project/status", (uri) => __awaiter(this, void 0, void 0, function* () {
|
|
196
|
-
var _a, _b, _c, _d, _e;
|
|
197
|
-
console.error(`SERVER.TS Resource request: ${uri.href}`);
|
|
198
|
-
try {
|
|
199
|
-
const scriptContent = yield (0, scriptLoader_1.loadScriptTemplate)('check_status');
|
|
200
|
-
const result = yield (0, codesys_interop_1.executeCodesysScript)(scriptContent, codesysExePath, codesysProfileName, sessionManager);
|
|
201
|
-
const outputLines = result.output.split(/[\r\n]+/).filter(line => line.trim());
|
|
202
|
-
const statusData = {};
|
|
203
|
-
outputLines.forEach(line => {
|
|
204
|
-
const match = line.match(/^([^:]+):\s*(.*)$/);
|
|
205
|
-
if (match) {
|
|
206
|
-
statusData[match[1].trim()] = match[2].trim();
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
const statusText = `CODESYS Status:\n - Scripting OK: ${(_a = statusData['Scripting OK']) !== null && _a !== void 0 ? _a : 'Unknown'}\n - Project Open: ${(_b = statusData['Project Open']) !== null && _b !== void 0 ? _b : 'Unknown'}\n - Project Name: ${(_c = statusData['Project Name']) !== null && _c !== void 0 ? _c : 'Unknown'}\n - Project Path: ${(_d = statusData['Project Path']) !== null && _d !== void 0 ? _d : 'N/A'}`;
|
|
210
|
-
const isError = !result.success || ((_e = statusData['Scripting OK']) === null || _e === void 0 ? void 0 : _e.toLowerCase()) !== 'true';
|
|
211
|
-
return { contents: [{ uri: uri.href, text: statusText, contentType: "text/plain" }], isError: isError };
|
|
212
|
-
}
|
|
213
|
-
catch (error) {
|
|
214
|
-
console.error(`Error resource ${uri.href}:`, error);
|
|
215
|
-
return { contents: [{ uri: uri.href, text: `Failed status script: ${error.message}`, contentType: "text/plain" }], isError: true };
|
|
216
|
-
}
|
|
217
|
-
}));
|
|
218
|
-
// Templates
|
|
219
|
-
const projectStructureTemplate = new mcp_js_1.ResourceTemplate("codesys://project/{+project_path}/structure", { list: undefined });
|
|
220
|
-
const pouCodeTemplate = new mcp_js_1.ResourceTemplate("codesys://project/{+project_path}/pou/{+pou_path}/code", { list: undefined });
|
|
221
|
-
server.resource("project-structure", projectStructureTemplate, (uri, params) => __awaiter(this, void 0, void 0, function* () {
|
|
222
|
-
const projectPathParam = params.project_path;
|
|
223
|
-
if (typeof projectPathParam !== 'string') {
|
|
224
|
-
return {
|
|
225
|
-
contents: [{ uri: uri.href, text: `Error: Invalid project path type (${typeof projectPathParam}).`, contentType: "text/plain" }],
|
|
226
|
-
isError: true
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
const projectPath = projectPathParam;
|
|
230
|
-
if (!projectPath) {
|
|
231
|
-
return {
|
|
232
|
-
contents: [{ uri: uri.href, text: "Error: Project path missing.", contentType: "text/plain" }],
|
|
233
|
-
isError: true
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
console.error(`Resource request: project structure for ${projectPath}`);
|
|
237
|
-
try {
|
|
238
|
-
const absoluteProjPath = path.normalize(path.isAbsolute(projectPath) ? projectPath : path.join(WORKSPACE_DIR, projectPath));
|
|
239
|
-
// Load script template and prepare parameters
|
|
240
|
-
const scriptTemplate = yield (0, scriptLoader_1.loadScriptTemplate)('get_project_structure');
|
|
241
|
-
const ensureProjectOpenTemplate = yield (0, scriptLoader_1.loadScriptTemplate)('ensure_project_open');
|
|
242
|
-
const combinedScript = ensureProjectOpenTemplate + '\n\n' + scriptTemplate;
|
|
243
|
-
const scriptContent = (0, scriptLoader_1.interpolateScript)(combinedScript, {
|
|
244
|
-
'PROJECT_FILE_PATH': absoluteProjPath.replace(/\\/g, '\\\\')
|
|
245
|
-
});
|
|
246
|
-
const result = yield (0, codesys_interop_1.executeCodesysScript)(scriptContent, codesysExePath, codesysProfileName, sessionManager);
|
|
247
|
-
let structureText = `Error retrieving structure for ${absoluteProjPath}.\n\n${result.output}`;
|
|
248
|
-
let isError = !result.success;
|
|
249
|
-
if (result.success && result.output.includes("SCRIPT_SUCCESS")) {
|
|
250
|
-
const startMarker = "--- PROJECT STRUCTURE START ---";
|
|
251
|
-
const endMarker = "--- PROJECT STRUCTURE END ---";
|
|
252
|
-
const startIndex = result.output.indexOf(startMarker);
|
|
253
|
-
const endIndex = result.output.indexOf(endMarker);
|
|
254
|
-
if (startIndex !== -1 && endIndex !== -1 && startIndex < endIndex) {
|
|
255
|
-
structureText = result.output.substring(startIndex + startMarker.length, endIndex).replace(/\\n/g, '\n').trim();
|
|
256
|
-
}
|
|
257
|
-
else {
|
|
258
|
-
console.error("Error: Could not find structure markers in script output.");
|
|
259
|
-
structureText = `Could not parse structure markers in output for ${absoluteProjPath}.\n\nOutput:\n${result.output}`;
|
|
260
|
-
isError = true;
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
else {
|
|
264
|
-
isError = true;
|
|
265
|
-
}
|
|
266
|
-
return { contents: [{ uri: uri.href, text: structureText, contentType: "text/plain" }], isError: isError };
|
|
267
|
-
}
|
|
268
|
-
catch (error) {
|
|
269
|
-
console.error(`Error getting structure ${uri.href}:`, error);
|
|
270
|
-
return { contents: [{ uri: uri.href, text: `Failed structure script for '${projectPath}': ${error.message}`, contentType: "text/plain" }], isError: true };
|
|
271
|
-
}
|
|
272
|
-
}));
|
|
273
|
-
server.resource("pou-code", pouCodeTemplate, (uri, params) => __awaiter(this, void 0, void 0, function* () {
|
|
274
|
-
const projectPathParam = params.project_path;
|
|
275
|
-
const pouPathParam = params.pou_path;
|
|
276
|
-
if (typeof projectPathParam !== 'string' || typeof pouPathParam !== 'string') {
|
|
277
|
-
return {
|
|
278
|
-
contents: [{ uri: uri.href, text: "Error: Invalid project or POU path type.", contentType: "text/plain" }],
|
|
279
|
-
isError: true
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
const projectPath = projectPathParam;
|
|
283
|
-
const pouPath = pouPathParam;
|
|
284
|
-
if (!projectPath || !pouPath) {
|
|
285
|
-
return {
|
|
286
|
-
contents: [{ uri: uri.href, text: "Error: Project or POU path missing.", contentType: "text/plain" }],
|
|
287
|
-
isError: true
|
|
288
|
-
};
|
|
289
|
-
}
|
|
290
|
-
console.error(`Resource request: POU code: Project='${projectPath}', POU='${pouPath}'`);
|
|
291
|
-
try {
|
|
292
|
-
const absoluteProjPath = path.normalize(path.isAbsolute(projectPath) ? projectPath : path.join(WORKSPACE_DIR, projectPath));
|
|
293
|
-
const sanitizedPouPath = String(pouPath).replace(/\\/g, '/').replace(/^\/+|\/+$/g, '');
|
|
294
|
-
// Load script template and prepare parameters
|
|
295
|
-
const scriptTemplate = yield (0, scriptLoader_1.loadScriptTemplate)('get_pou_code');
|
|
296
|
-
const ensureProjectOpenTemplate = yield (0, scriptLoader_1.loadScriptTemplate)('ensure_project_open');
|
|
297
|
-
const findObjectByPathTemplate = yield (0, scriptLoader_1.loadScriptTemplate)('find_object_by_path');
|
|
298
|
-
const combinedScript = ensureProjectOpenTemplate + '\n\n' + findObjectByPathTemplate + '\n\n' + scriptTemplate;
|
|
299
|
-
const scriptContent = (0, scriptLoader_1.interpolateScript)(combinedScript, {
|
|
300
|
-
'PROJECT_FILE_PATH': absoluteProjPath.replace(/\\/g, '\\\\'),
|
|
301
|
-
'POU_FULL_PATH': sanitizedPouPath
|
|
302
|
-
});
|
|
303
|
-
const result = yield (0, codesys_interop_1.executeCodesysScript)(scriptContent, codesysExePath, codesysProfileName, sessionManager);
|
|
304
|
-
let codeText = `Error retrieving code for object '${sanitizedPouPath}' in project '${absoluteProjPath}'.\n\n${result.output}`;
|
|
305
|
-
let isError = !result.success;
|
|
306
|
-
if (result.success && result.output.includes("SCRIPT_SUCCESS")) {
|
|
307
|
-
const declStartMarker = "### POU DECLARATION START ###";
|
|
308
|
-
const declEndMarker = "### POU DECLARATION END ###";
|
|
309
|
-
const implStartMarker = "### POU IMPLEMENTATION START ###";
|
|
310
|
-
const implEndMarker = "### POU IMPLEMENTATION END ###";
|
|
311
|
-
const declStartIdx = result.output.indexOf(declStartMarker);
|
|
312
|
-
const declEndIdx = result.output.indexOf(declEndMarker);
|
|
313
|
-
const implStartIdx = result.output.indexOf(implStartMarker);
|
|
314
|
-
const implEndIdx = result.output.indexOf(implEndMarker);
|
|
315
|
-
let declaration = "/* Declaration not found in output */";
|
|
316
|
-
let implementation = "/* Implementation not found in output */";
|
|
317
|
-
if (declStartIdx !== -1 && declEndIdx !== -1 && declStartIdx < declEndIdx) {
|
|
318
|
-
declaration = result.output.substring(declStartIdx + declStartMarker.length, declEndIdx).replace(/\\n/g, '\n').trim();
|
|
319
|
-
}
|
|
320
|
-
else {
|
|
321
|
-
console.error(`WARN: Declaration markers not found correctly for ${sanitizedPouPath}`);
|
|
322
|
-
}
|
|
323
|
-
if (implStartIdx !== -1 && implEndIdx !== -1 && implStartIdx < implEndIdx) {
|
|
324
|
-
implementation = result.output.substring(implStartIdx + implStartMarker.length, implEndIdx).replace(/\\n/g, '\n').trim();
|
|
325
|
-
}
|
|
326
|
-
else {
|
|
327
|
-
console.error(`WARN: Implementation markers not found correctly for ${sanitizedPouPath}`);
|
|
328
|
-
}
|
|
329
|
-
codeText = `// ----- Declaration -----\n${declaration}\n\n// ----- Implementation -----\n${implementation}`;
|
|
330
|
-
}
|
|
331
|
-
else {
|
|
332
|
-
isError = true;
|
|
333
|
-
}
|
|
334
|
-
return { contents: [{ uri: uri.href, text: codeText, contentType: "text/plain" }], isError: isError };
|
|
335
|
-
}
|
|
336
|
-
catch (error) {
|
|
337
|
-
console.error(`Error getting POU code ${uri.href}:`, error);
|
|
338
|
-
return { contents: [{ uri: uri.href, text: `Failed POU code script for '${pouPath}' in '${projectPath}': ${error.message}`, contentType: "text/plain" }], isError: true };
|
|
339
|
-
}
|
|
340
|
-
}));
|
|
341
|
-
// --- End Resources ---
|
|
342
|
-
// --- Tools ---
|
|
343
|
-
server.tool("open_project", "Opens an existing CODESYS project file.", {
|
|
344
|
-
filePath: zod_1.z.string().describe("Path to the project file (e.g., 'C:/Projects/MyPLC.project' or '/Users/user/projects/my_project.project').")
|
|
345
|
-
}, (args) => __awaiter(this, void 0, void 0, function* () {
|
|
346
|
-
const { filePath } = args;
|
|
347
|
-
let absPath = path.normalize(path.isAbsolute(filePath) ? filePath : path.join(WORKSPACE_DIR, filePath));
|
|
348
|
-
console.error(`Tool call: open_project: ${absPath}`);
|
|
349
|
-
try {
|
|
350
|
-
// Load the script template and prepare with parameters
|
|
351
|
-
const scriptTemplate = yield (0, scriptLoader_1.loadScriptTemplate)('open_project');
|
|
352
|
-
// Combine with required ensure_project_open script (will handle any imports)
|
|
353
|
-
const ensureProjectOpenScript = yield (0, scriptLoader_1.loadScriptTemplate)('ensure_project_open');
|
|
354
|
-
const combinedScript = ensureProjectOpenScript + '\n\n' + scriptTemplate;
|
|
355
|
-
const scriptContent = (0, scriptLoader_1.interpolateScript)(combinedScript, {
|
|
356
|
-
'PROJECT_FILE_PATH': absPath.replace(/\\/g, '\\\\')
|
|
357
|
-
});
|
|
358
|
-
const result = yield (0, codesys_interop_1.executeCodesysScript)(scriptContent, codesysExePath, codesysProfileName, sessionManager);
|
|
359
|
-
const success = result.success && result.output.includes("SCRIPT_SUCCESS");
|
|
360
|
-
return {
|
|
361
|
-
content: [{
|
|
362
|
-
type: "text",
|
|
363
|
-
text: success ? `Project opened: ${absPath}` : `Failed open project ${absPath}. Output:\n${result.output}`
|
|
364
|
-
}],
|
|
365
|
-
isError: !success
|
|
366
|
-
};
|
|
367
|
-
}
|
|
368
|
-
catch (e) {
|
|
369
|
-
console.error(`Error open_project ${absPath}: ${e}`);
|
|
370
|
-
return {
|
|
371
|
-
content: [{ type: "text", text: `Error: ${e.message}` }],
|
|
372
|
-
isError: true
|
|
373
|
-
};
|
|
374
|
-
}
|
|
375
|
-
}));
|
|
376
|
-
server.tool("create_project", "Creates a new CODESYS project from the standard template.", {
|
|
377
|
-
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').")
|
|
378
|
-
}, (args) => __awaiter(this, void 0, void 0, function* () {
|
|
379
|
-
const { filePath } = args;
|
|
380
|
-
let absPath = path.normalize(path.isAbsolute(filePath) ? filePath : path.join(WORKSPACE_DIR, filePath));
|
|
381
|
-
console.error(`Tool call: create_project (copy template): ${absPath}`);
|
|
382
|
-
let templatePath = "";
|
|
383
|
-
try {
|
|
384
|
-
// Template finding logic
|
|
385
|
-
const baseDir = path.dirname(path.dirname(codesysExePath));
|
|
386
|
-
templatePath = path.normalize(path.join(baseDir, 'Templates', 'Standard.project'));
|
|
387
|
-
if (!(yield fileExists(templatePath))) {
|
|
388
|
-
console.error(`WARN: Template not found relative to exe: ${templatePath}. Trying ProgramData...`);
|
|
389
|
-
const programData = process.env.ALLUSERSPROFILE || process.env.ProgramData || 'C:\\ProgramData';
|
|
390
|
-
const possibleTemplateDir = path.join(programData, 'CODESYS', 'CODESYS', codesysProfileName, 'Templates');
|
|
391
|
-
let potentialTemplatePath = path.normalize(path.join(possibleTemplateDir, 'Standard.project'));
|
|
392
|
-
if (yield fileExists(potentialTemplatePath)) {
|
|
393
|
-
templatePath = potentialTemplatePath;
|
|
394
|
-
console.error(`DEBUG: Found template in ProgramData: ${templatePath}`);
|
|
395
|
-
}
|
|
396
|
-
else {
|
|
397
|
-
const alternativeTemplateDir = path.join(programData, 'CODESYS', 'Templates');
|
|
398
|
-
potentialTemplatePath = path.normalize(path.join(alternativeTemplateDir, 'Standard.project'));
|
|
399
|
-
if (yield fileExists(potentialTemplatePath)) {
|
|
400
|
-
templatePath = potentialTemplatePath;
|
|
401
|
-
console.error(`DEBUG: Found template in ProgramData (alternative): ${templatePath}`);
|
|
402
|
-
}
|
|
403
|
-
else {
|
|
404
|
-
throw new Error(`Standard template project file not found at relative path or ProgramData locations.`);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
else {
|
|
409
|
-
console.error(`DEBUG: Found template relative to exe: ${templatePath}`);
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
catch (e) {
|
|
413
|
-
console.error(`Template Error: ${e.message}`);
|
|
414
|
-
return {
|
|
415
|
-
content: [{ type: "text", text: `Template Error: ${e.message}` }],
|
|
416
|
-
isError: true
|
|
417
|
-
};
|
|
418
|
-
}
|
|
419
|
-
try {
|
|
420
|
-
// Load script template and interpolate parameters
|
|
421
|
-
const scriptTemplate = yield (0, scriptLoader_1.loadScriptTemplate)('create_project');
|
|
422
|
-
// Normalize paths for more consistent handling between platforms
|
|
423
|
-
const normalizedTargetPath = absPath.replace(/\\/g, '/');
|
|
424
|
-
const normalizedTemplatePath = templatePath.replace(/\\/g, '/');
|
|
425
|
-
console.error(`Using normalized paths for script: Target=${normalizedTargetPath}, Template=${normalizedTemplatePath}`);
|
|
426
|
-
// When running in a session, skip the open step to avoid conflicts
|
|
427
|
-
const inSession = sessionManager &&
|
|
428
|
-
(sessionManager.getState() === sessionManager_1.SessionState.RUNNING ||
|
|
429
|
-
sessionManager.getState() === sessionManager_1.SessionState.BUSY);
|
|
430
|
-
const scriptContent = (0, scriptLoader_1.interpolateScript)(scriptTemplate, {
|
|
431
|
-
'PROJECT_FILE_PATH': normalizedTargetPath,
|
|
432
|
-
'TEMPLATE_PROJECT_PATH': normalizedTemplatePath,
|
|
433
|
-
'SKIP_OPEN': inSession ? 'true' : 'false'
|
|
434
|
-
});
|
|
435
|
-
console.error(">>> create_project (copy-then-open): PREPARED SCRIPT:", scriptContent.substring(0, 500) + "...");
|
|
436
|
-
// Try the direct session approach first if a session is active
|
|
437
|
-
let result;
|
|
438
|
-
let usingDirectSession = false;
|
|
439
|
-
// Check if there's an active session using our direct method
|
|
440
|
-
if ((0, direct_session_command_1.isSessionActive)()) {
|
|
441
|
-
console.error(">>> create_project: Detected active session, using direct command approach");
|
|
442
|
-
try {
|
|
443
|
-
// Use our direct session command approach
|
|
444
|
-
usingDirectSession = true;
|
|
445
|
-
const directResult = yield (0, direct_session_command_1.createProjectDirect)(normalizedTargetPath, normalizedTemplatePath);
|
|
446
|
-
if (directResult.success) {
|
|
447
|
-
// Format the result to match the expected format
|
|
448
|
-
result = {
|
|
449
|
-
success: true,
|
|
450
|
-
output: `SCRIPT_SUCCESS: Project created from template using direct session command.\n${directResult.message}`
|
|
451
|
-
};
|
|
452
|
-
console.error(">>> create_project: Direct session command succeeded");
|
|
453
|
-
}
|
|
454
|
-
else {
|
|
455
|
-
console.error(`>>> create_project: Direct session command failed: ${directResult.message}`);
|
|
456
|
-
// Fall back to regular script execution
|
|
457
|
-
usingDirectSession = false;
|
|
458
|
-
result = yield (0, codesys_interop_1.executeCodesysScript)(scriptContent, codesysExePath, codesysProfileName);
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
catch (directError) {
|
|
462
|
-
console.error(`>>> create_project: Error with direct session command: ${directError.message}`);
|
|
463
|
-
// Fall back to regular script execution
|
|
464
|
-
usingDirectSession = false;
|
|
465
|
-
result = yield (0, codesys_interop_1.executeCodesysScript)(scriptContent, codesysExePath, codesysProfileName);
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
// If not using direct session, use the standard approach
|
|
469
|
-
if (!usingDirectSession) {
|
|
470
|
-
// Use a longer timeout for project creation operations (120 seconds)
|
|
471
|
-
console.error(">>> create_project: Using standard script execution");
|
|
472
|
-
result = yield (0, codesys_interop_1.executeCodesysScript)(scriptContent, codesysExePath, codesysProfileName, sessionManager);
|
|
473
|
-
}
|
|
474
|
-
console.error(">>> create_project (copy-then-open): EXECUTION RESULT:", JSON.stringify(result));
|
|
475
|
-
// Check if there was a timeout but the project might still have been created
|
|
476
|
-
if (!result.success && result.output.includes("timed out") && result.output.includes("project file might still have been created")) {
|
|
477
|
-
console.error(">>> create_project: Script timed out but project might have been created. Checking if file exists.");
|
|
478
|
-
// Check if the project file was actually created despite the timeout
|
|
479
|
-
const fileExists = fs.existsSync(absPath);
|
|
480
|
-
if (fileExists) {
|
|
481
|
-
console.error(`>>> create_project: Project file ${absPath} exists despite timeout.`);
|
|
482
|
-
return {
|
|
483
|
-
content: [{
|
|
484
|
-
type: "text",
|
|
485
|
-
text: `Project file was created at ${absPath}, but the operation timed out before completion. ` +
|
|
486
|
-
`The project might be usable, but you may need to manually open it in CODESYS.`
|
|
487
|
-
}],
|
|
488
|
-
isError: true // Still mark as error because operation didn't complete properly
|
|
489
|
-
};
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
const success = result.success && result.output.includes("SCRIPT_SUCCESS");
|
|
493
|
-
// Special handling for cases where project was created but couldn't be opened automatically
|
|
494
|
-
if (success && inSession && result.output.includes("open operation failed")) {
|
|
495
|
-
return {
|
|
496
|
-
content: [{
|
|
497
|
-
type: "text",
|
|
498
|
-
text: `Project created from template: ${absPath}\n` +
|
|
499
|
-
`Note: The project was created successfully, but couldn't be opened automatically because you're in a session.\n` +
|
|
500
|
-
`You can use open_project to open it now, or create a POU directly with create_pou.`
|
|
501
|
-
}],
|
|
502
|
-
isError: false
|
|
503
|
-
};
|
|
504
|
-
}
|
|
505
|
-
// Special handling for skipped open operations in sessions
|
|
506
|
-
if (success && inSession && result.output.includes("open step skipped for session compatibility")) {
|
|
507
|
-
return {
|
|
508
|
-
content: [{
|
|
509
|
-
type: "text",
|
|
510
|
-
text: `Project created from template: ${absPath}\n` +
|
|
511
|
-
`Note: The project opening step was skipped because you're in a session.\n` +
|
|
512
|
-
`You can use open_project to open it now, or create a POU directly with create_pou.`
|
|
513
|
-
}],
|
|
514
|
-
isError: false
|
|
515
|
-
};
|
|
516
|
-
}
|
|
517
|
-
return {
|
|
518
|
-
content: [{
|
|
519
|
-
type: "text",
|
|
520
|
-
text: success ? `Project created from template: ${absPath}` : `Failed create project ${absPath} from template. Output:\n${result.output}`
|
|
521
|
-
}],
|
|
522
|
-
isError: !success
|
|
523
|
-
};
|
|
524
|
-
}
|
|
525
|
-
catch (e) {
|
|
526
|
-
console.error(`Error create_project ${absPath}: ${e}`);
|
|
527
|
-
return {
|
|
528
|
-
content: [{ type: "text", text: `Error: ${e.message}` }],
|
|
529
|
-
isError: true
|
|
530
|
-
};
|
|
531
|
-
}
|
|
532
|
-
}));
|
|
533
|
-
server.tool("save_project", "Saves the currently open CODESYS project.", {
|
|
534
|
-
projectFilePath: zod_1.z.string().describe("Path to the project file to ensure is open before saving (e.g., 'C:/Projects/MyPLC.project').")
|
|
535
|
-
}, (args) => __awaiter(this, void 0, void 0, function* () {
|
|
536
|
-
const { projectFilePath } = args;
|
|
537
|
-
let absPath = path.normalize(path.isAbsolute(projectFilePath) ? projectFilePath : path.join(WORKSPACE_DIR, projectFilePath));
|
|
538
|
-
console.error(`Tool call: save_project: ${absPath}`);
|
|
539
|
-
try {
|
|
540
|
-
// Load and combine script templates
|
|
541
|
-
const saveProjectTemplate = yield (0, scriptLoader_1.loadScriptTemplate)('save_project');
|
|
542
|
-
const ensureProjectOpenTemplate = yield (0, scriptLoader_1.loadScriptTemplate)('ensure_project_open');
|
|
543
|
-
const combinedScript = ensureProjectOpenTemplate + '\n\n' + saveProjectTemplate;
|
|
544
|
-
const scriptContent = (0, scriptLoader_1.interpolateScript)(combinedScript, {
|
|
545
|
-
'PROJECT_FILE_PATH': absPath.replace(/\\/g, '\\\\')
|
|
546
|
-
});
|
|
547
|
-
const result = yield (0, codesys_interop_1.executeCodesysScript)(scriptContent, codesysExePath, codesysProfileName, sessionManager);
|
|
548
|
-
const success = result.success && result.output.includes("SCRIPT_SUCCESS");
|
|
549
|
-
return {
|
|
550
|
-
content: [{
|
|
551
|
-
type: "text",
|
|
552
|
-
text: success ? `Project saved: ${absPath}` : `Failed save project ${absPath}. Output:\n${result.output}`
|
|
553
|
-
}],
|
|
554
|
-
isError: !success
|
|
555
|
-
};
|
|
556
|
-
}
|
|
557
|
-
catch (e) {
|
|
558
|
-
console.error(`Error save_project ${absPath}: ${e}`);
|
|
559
|
-
return {
|
|
560
|
-
content: [{ type: "text", text: `Error: ${e.message}` }],
|
|
561
|
-
isError: true
|
|
562
|
-
};
|
|
563
|
-
}
|
|
564
|
-
}));
|
|
565
|
-
server.tool("create_pou", "Creates a new Program, Function Block, or Function POU within the specified CODESYS project.", {
|
|
566
|
-
projectFilePath: zod_1.z.string().describe("Path to the project file (e.g., 'C:/Projects/MyPLC.project')."),
|
|
567
|
-
name: zod_1.z.string().describe("Name for the new POU (must be a valid IEC identifier)."),
|
|
568
|
-
type: PouTypeEnum.describe("Type of POU (Program, FunctionBlock, Function)."),
|
|
569
|
-
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."),
|
|
570
|
-
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').")
|
|
571
|
-
}, (args) => __awaiter(this, void 0, void 0, function* () {
|
|
572
|
-
const { projectFilePath, name, type, language, parentPath } = args;
|
|
573
|
-
let absPath = path.normalize(path.isAbsolute(projectFilePath) ? projectFilePath : path.join(WORKSPACE_DIR, projectFilePath));
|
|
574
|
-
const sanParentPath = parentPath.replace(/\\/g, '/').replace(/^\/+|\/+$/g, '');
|
|
575
|
-
const sanName = name.trim();
|
|
576
|
-
console.error(`Tool call: create_pou: Name='${sanName}', Type='${type}', Lang='${language}', Parent='${sanParentPath}', Project='${absPath}'`);
|
|
577
|
-
try {
|
|
578
|
-
// Load and combine script templates
|
|
579
|
-
const createPouTemplate = yield (0, scriptLoader_1.loadScriptTemplate)('create_pou');
|
|
580
|
-
const ensureProjectOpenTemplate = yield (0, scriptLoader_1.loadScriptTemplate)('ensure_project_open');
|
|
581
|
-
const findObjectByPathTemplate = yield (0, scriptLoader_1.loadScriptTemplate)('find_object_by_path');
|
|
582
|
-
const combinedScript = ensureProjectOpenTemplate + '\n\n' + findObjectByPathTemplate + '\n\n' + createPouTemplate;
|
|
583
|
-
const scriptContent = (0, scriptLoader_1.interpolateScript)(combinedScript, {
|
|
584
|
-
'PROJECT_FILE_PATH': absPath.replace(/\\/g, '\\\\'),
|
|
585
|
-
'POU_NAME': sanName,
|
|
586
|
-
'POU_TYPE_STR': type,
|
|
587
|
-
'IMPL_LANGUAGE_STR': language,
|
|
588
|
-
'PARENT_PATH': sanParentPath
|
|
589
|
-
});
|
|
590
|
-
console.error(">>> create_pou: PREPARED SCRIPT:", scriptContent.substring(0, 500) + "...");
|
|
591
|
-
const result = yield (0, codesys_interop_1.executeCodesysScript)(scriptContent, codesysExePath, codesysProfileName, sessionManager);
|
|
592
|
-
console.error(">>> create_pou: EXECUTION RESULT:", JSON.stringify(result));
|
|
593
|
-
const success = result.success && result.output.includes("SCRIPT_SUCCESS");
|
|
594
|
-
return {
|
|
595
|
-
content: [{
|
|
596
|
-
type: "text",
|
|
597
|
-
text: success ? `POU '${sanName}' created in '${sanParentPath}' of ${absPath}. Project saved.` : `Failed create POU '${sanName}'. Output:\n${result.output}`
|
|
598
|
-
}],
|
|
599
|
-
isError: !success
|
|
600
|
-
};
|
|
601
|
-
}
|
|
602
|
-
catch (e) {
|
|
603
|
-
console.error(`Error create_pou ${sanName} in ${absPath}: ${e}`);
|
|
604
|
-
return {
|
|
605
|
-
content: [{ type: "text", text: `Error: ${e.message}` }],
|
|
606
|
-
isError: true
|
|
607
|
-
};
|
|
608
|
-
}
|
|
609
|
-
}));
|
|
610
|
-
server.tool("set_pou_code", "Sets the declaration and/or implementation code for a specific POU, Method, or Property.", {
|
|
611
|
-
projectFilePath: zod_1.z.string().describe("Path to the project file (e.g., 'C:/Projects/MyPLC.project')."),
|
|
612
|
-
pouPath: zod_1.z.string().describe("Full relative path to the target object (e.g., 'Application/MyPOU', 'MyFolder/MyFB/MyMethod', 'MyFolder/MyFB/MyProperty')."),
|
|
613
|
-
declarationCode: zod_1.z.string().describe("Code for the declaration part (VAR...END_VAR). If omitted, the declaration is not changed.").optional(),
|
|
614
|
-
implementationCode: zod_1.z.string().describe("Code for the implementation logic part. If omitted, the implementation is not changed.").optional()
|
|
615
|
-
}, (args) => __awaiter(this, void 0, void 0, function* () {
|
|
616
|
-
const { projectFilePath, pouPath, declarationCode, implementationCode } = args;
|
|
617
|
-
if (declarationCode === undefined && implementationCode === undefined) {
|
|
618
|
-
return {
|
|
619
|
-
content: [{ type: "text", text: "Error: At least one of declarationCode or implementationCode must be provided." }],
|
|
620
|
-
isError: true
|
|
621
|
-
};
|
|
622
|
-
}
|
|
623
|
-
let absPath = path.normalize(path.isAbsolute(projectFilePath) ? projectFilePath : path.join(WORKSPACE_DIR, projectFilePath));
|
|
624
|
-
const sanPouPath = pouPath.replace(/\\/g, '/').replace(/^\/+|\/+$/g, '');
|
|
625
|
-
console.error(`Tool call: set_pou_code: Target='${sanPouPath}', Project='${absPath}'`);
|
|
626
|
-
try {
|
|
627
|
-
// Load and combine script templates
|
|
628
|
-
const setPouCodeTemplate = yield (0, scriptLoader_1.loadScriptTemplate)('set_pou_code');
|
|
629
|
-
const ensureProjectOpenTemplate = yield (0, scriptLoader_1.loadScriptTemplate)('ensure_project_open');
|
|
630
|
-
const findObjectByPathTemplate = yield (0, scriptLoader_1.loadScriptTemplate)('find_object_by_path');
|
|
631
|
-
const combinedScript = ensureProjectOpenTemplate + '\n\n' + findObjectByPathTemplate + '\n\n' + setPouCodeTemplate;
|
|
632
|
-
// Escape content for Python triple-quoted strings
|
|
633
|
-
const sanDeclCode = (declarationCode !== null && declarationCode !== void 0 ? declarationCode : "").replace(/\\/g, '\\\\').replace(/"""/g, '\\"\\"\\"');
|
|
634
|
-
const sanImplCode = (implementationCode !== null && implementationCode !== void 0 ? implementationCode : "").replace(/\\/g, '\\\\').replace(/"""/g, '\\"\\"\\"');
|
|
635
|
-
const scriptContent = (0, scriptLoader_1.interpolateScript)(combinedScript, {
|
|
636
|
-
'PROJECT_FILE_PATH': absPath.replace(/\\/g, '\\\\'),
|
|
637
|
-
'POU_FULL_PATH': sanPouPath,
|
|
638
|
-
'DECLARATION_CONTENT': sanDeclCode,
|
|
639
|
-
'IMPLEMENTATION_CONTENT': sanImplCode
|
|
640
|
-
});
|
|
641
|
-
console.error(">>> set_pou_code: PREPARED SCRIPT:", scriptContent.substring(0, 500) + "...");
|
|
642
|
-
const result = yield (0, codesys_interop_1.executeCodesysScript)(scriptContent, codesysExePath, codesysProfileName, sessionManager);
|
|
643
|
-
console.error(">>> set_pou_code: EXECUTION RESULT:", JSON.stringify(result));
|
|
644
|
-
const success = result.success && result.output.includes("SCRIPT_SUCCESS");
|
|
645
|
-
return {
|
|
646
|
-
content: [{
|
|
647
|
-
type: "text",
|
|
648
|
-
text: success ? `Code set for '${sanPouPath}' in ${absPath}. Project saved.` : `Failed set code for '${sanPouPath}'. Output:\n${result.output}`
|
|
649
|
-
}],
|
|
650
|
-
isError: !success
|
|
651
|
-
};
|
|
652
|
-
}
|
|
653
|
-
catch (e) {
|
|
654
|
-
console.error(`Error set_pou_code ${sanPouPath} in ${absPath}: ${e}`);
|
|
655
|
-
return {
|
|
656
|
-
content: [{ type: "text", text: `Error: ${e.message}` }],
|
|
657
|
-
isError: true
|
|
658
|
-
};
|
|
659
|
-
}
|
|
660
|
-
}));
|
|
661
|
-
server.tool("create_property", "Creates a new Property within a specific Function Block POU.", {
|
|
662
|
-
projectFilePath: zod_1.z.string().describe("Path to the project file (e.g., 'C:/Projects/MyPLC.project')."),
|
|
663
|
-
parentPouPath: zod_1.z.string().describe("Relative path to the parent Function Block POU (e.g., 'Application/MyFB')."),
|
|
664
|
-
propertyName: zod_1.z.string().describe("Name for the new property (must be a valid IEC identifier)."),
|
|
665
|
-
propertyType: zod_1.z.string().describe("Data type of the property (e.g., 'BOOL', 'INT', 'MyDUT').")
|
|
666
|
-
}, (args) => __awaiter(this, void 0, void 0, function* () {
|
|
667
|
-
const { projectFilePath, parentPouPath, propertyName, propertyType } = args;
|
|
668
|
-
let absPath = path.normalize(path.isAbsolute(projectFilePath) ? projectFilePath : path.join(WORKSPACE_DIR, projectFilePath));
|
|
669
|
-
const sanParentPath = parentPouPath.replace(/\\/g, '/').replace(/^\/+|\/+$/g, '');
|
|
670
|
-
const sanPropName = propertyName.trim();
|
|
671
|
-
const sanPropType = propertyType.trim();
|
|
672
|
-
console.error(`Tool call: create_property: Name='${sanPropName}', Type='${sanPropType}', ParentPOU='${sanParentPath}', Project='${absPath}'`);
|
|
673
|
-
if (!sanPropName || !sanPropType) {
|
|
674
|
-
return {
|
|
675
|
-
content: [{ type: "text", text: `Error: Property name and type cannot be empty.` }],
|
|
676
|
-
isError: true
|
|
677
|
-
};
|
|
678
|
-
}
|
|
679
|
-
try {
|
|
680
|
-
// Load and combine script templates
|
|
681
|
-
const createPropertyTemplate = yield (0, scriptLoader_1.loadScriptTemplate)('create_property');
|
|
682
|
-
const ensureProjectOpenTemplate = yield (0, scriptLoader_1.loadScriptTemplate)('ensure_project_open');
|
|
683
|
-
const findObjectByPathTemplate = yield (0, scriptLoader_1.loadScriptTemplate)('find_object_by_path');
|
|
684
|
-
const combinedScript = ensureProjectOpenTemplate + '\n\n' + findObjectByPathTemplate + '\n\n' + createPropertyTemplate;
|
|
685
|
-
const scriptContent = (0, scriptLoader_1.interpolateScript)(combinedScript, {
|
|
686
|
-
'PROJECT_FILE_PATH': absPath.replace(/\\/g, '\\\\'),
|
|
687
|
-
'PARENT_POU_FULL_PATH': sanParentPath,
|
|
688
|
-
'PROPERTY_NAME': sanPropName,
|
|
689
|
-
'PROPERTY_TYPE': sanPropType
|
|
690
|
-
});
|
|
691
|
-
console.error(">>> create_property: PREPARED SCRIPT:", scriptContent.substring(0, 500) + "...");
|
|
692
|
-
const result = yield (0, codesys_interop_1.executeCodesysScript)(scriptContent, codesysExePath, codesysProfileName, sessionManager);
|
|
693
|
-
console.error(">>> create_property: EXECUTION RESULT:", JSON.stringify(result));
|
|
694
|
-
const success = result.success && result.output.includes("SCRIPT_SUCCESS");
|
|
695
|
-
return {
|
|
696
|
-
content: [{
|
|
697
|
-
type: "text",
|
|
698
|
-
text: success ? `Property '${sanPropName}' created under '${sanParentPath}' in ${absPath}. Project saved.` : `Failed to create property '${sanPropName}'. Output:\n${result.output}`
|
|
699
|
-
}],
|
|
700
|
-
isError: !success
|
|
701
|
-
};
|
|
702
|
-
}
|
|
703
|
-
catch (e) {
|
|
704
|
-
console.error(`Error create_property ${sanPropName} in ${absPath}: ${e}`);
|
|
705
|
-
return {
|
|
706
|
-
content: [{ type: "text", text: `Error: ${e.message}` }],
|
|
707
|
-
isError: true
|
|
708
|
-
};
|
|
709
|
-
}
|
|
710
|
-
}));
|
|
711
|
-
server.tool("create_method", "Creates a new Method within a specific Function Block POU.", {
|
|
712
|
-
projectFilePath: zod_1.z.string().describe("Path to the project file (e.g., 'C:/Projects/MyPLC.project')."),
|
|
713
|
-
parentPouPath: zod_1.z.string().describe("Relative path to the parent Function Block POU (e.g., 'Application/MyFB')."),
|
|
714
|
-
methodName: zod_1.z.string().describe("Name of the new method (must be a valid IEC identifier)."),
|
|
715
|
-
returnType: zod_1.z.string().optional().describe("Return type (e.g., 'BOOL', 'INT'). Leave empty or omit for no return value (PROCEDURE).")
|
|
716
|
-
}, (args) => __awaiter(this, void 0, void 0, function* () {
|
|
717
|
-
const { projectFilePath, parentPouPath, methodName, returnType } = args;
|
|
718
|
-
let absPath = path.normalize(path.isAbsolute(projectFilePath) ? projectFilePath : path.join(WORKSPACE_DIR, projectFilePath));
|
|
719
|
-
const sanParentPath = parentPouPath.replace(/\\/g, '/').replace(/^\/+|\/+$/g, '');
|
|
720
|
-
const sanMethName = methodName.trim();
|
|
721
|
-
const sanReturnType = (returnType !== null && returnType !== void 0 ? returnType : "").trim();
|
|
722
|
-
console.error(`Tool call: create_method: Name='${sanMethName}', Return='${sanReturnType}', ParentPOU='${sanParentPath}', Project='${absPath}'`);
|
|
723
|
-
if (!sanMethName) {
|
|
724
|
-
return {
|
|
725
|
-
content: [{ type: "text", text: `Error: Method name cannot be empty.` }],
|
|
726
|
-
isError: true
|
|
727
|
-
};
|
|
728
|
-
}
|
|
729
|
-
try {
|
|
730
|
-
// Load and combine script templates
|
|
731
|
-
const createMethodTemplate = yield (0, scriptLoader_1.loadScriptTemplate)('create_method');
|
|
732
|
-
const ensureProjectOpenTemplate = yield (0, scriptLoader_1.loadScriptTemplate)('ensure_project_open');
|
|
733
|
-
const findObjectByPathTemplate = yield (0, scriptLoader_1.loadScriptTemplate)('find_object_by_path');
|
|
734
|
-
const combinedScript = ensureProjectOpenTemplate + '\n\n' + findObjectByPathTemplate + '\n\n' + createMethodTemplate;
|
|
735
|
-
const scriptContent = (0, scriptLoader_1.interpolateScript)(combinedScript, {
|
|
736
|
-
'PROJECT_FILE_PATH': absPath.replace(/\\/g, '\\\\'),
|
|
737
|
-
'PARENT_POU_FULL_PATH': sanParentPath,
|
|
738
|
-
'METHOD_NAME': sanMethName,
|
|
739
|
-
'RETURN_TYPE': sanReturnType
|
|
740
|
-
});
|
|
741
|
-
console.error(">>> create_method: PREPARED SCRIPT:", scriptContent.substring(0, 500) + "...");
|
|
742
|
-
const result = yield (0, codesys_interop_1.executeCodesysScript)(scriptContent, codesysExePath, codesysProfileName, sessionManager);
|
|
743
|
-
console.error(">>> create_method: EXECUTION RESULT:", JSON.stringify(result));
|
|
744
|
-
const success = result.success && result.output.includes("SCRIPT_SUCCESS");
|
|
745
|
-
return {
|
|
746
|
-
content: [{
|
|
747
|
-
type: "text",
|
|
748
|
-
text: success ? `Method '${sanMethName}' created under '${sanParentPath}' in ${absPath}. Project saved.` : `Failed to create method '${sanMethName}'. Output:\n${result.output}`
|
|
749
|
-
}],
|
|
750
|
-
isError: !success
|
|
751
|
-
};
|
|
752
|
-
}
|
|
753
|
-
catch (e) {
|
|
754
|
-
console.error(`Error create_method ${sanMethName} in ${absPath}: ${e}`);
|
|
755
|
-
return {
|
|
756
|
-
content: [{ type: "text", text: `Error: ${e.message}` }],
|
|
757
|
-
isError: true
|
|
758
|
-
};
|
|
759
|
-
}
|
|
760
|
-
}));
|
|
761
|
-
server.tool("compile_project", "Compiles (Builds) the primary application within a CODESYS project.", {
|
|
762
|
-
projectFilePath: zod_1.z.string().describe("Path to the project file containing the application to compile (e.g., 'C:/Projects/MyPLC.project').")
|
|
763
|
-
}, (args) => __awaiter(this, void 0, void 0, function* () {
|
|
764
|
-
const { projectFilePath } = args;
|
|
765
|
-
let absPath = path.normalize(path.isAbsolute(projectFilePath) ? projectFilePath : path.join(WORKSPACE_DIR, projectFilePath));
|
|
766
|
-
console.error(`Tool call: compile_project: ${absPath}`);
|
|
767
|
-
try {
|
|
768
|
-
// Load and combine script templates
|
|
769
|
-
const compileProjectTemplate = yield (0, scriptLoader_1.loadScriptTemplate)('compile_project');
|
|
770
|
-
const ensureProjectOpenTemplate = yield (0, scriptLoader_1.loadScriptTemplate)('ensure_project_open');
|
|
771
|
-
const combinedScript = ensureProjectOpenTemplate + '\n\n' + compileProjectTemplate;
|
|
772
|
-
const scriptContent = (0, scriptLoader_1.interpolateScript)(combinedScript, {
|
|
773
|
-
'PROJECT_FILE_PATH': absPath.replace(/\\/g, '\\\\')
|
|
774
|
-
});
|
|
775
|
-
const result = yield (0, codesys_interop_1.executeCodesysScript)(scriptContent, codesysExePath, codesysProfileName, sessionManager);
|
|
776
|
-
const success = result.success && result.output.includes("SCRIPT_SUCCESS");
|
|
777
|
-
// Check for actual compile errors in the output log
|
|
778
|
-
const hasCompileErrors = result.output.includes("Compile complete --") && !/ 0 error\(s\),/.test(result.output);
|
|
779
|
-
let message = success ? `Compilation initiated for application in ${absPath}. Check CODESYS messages for results.` : `Failed initiating compilation for ${absPath}. Output:\n${result.output}`;
|
|
780
|
-
let isError = !success; // Base error status on script success
|
|
781
|
-
if (success && hasCompileErrors) {
|
|
782
|
-
message += " WARNING: Build command reported errors in the output log.";
|
|
783
|
-
console.warn("Compile project reported build errors in the output.");
|
|
784
|
-
// Report as error if compile fails, even if script technically succeeded
|
|
785
|
-
isError = true;
|
|
786
|
-
}
|
|
787
|
-
return {
|
|
788
|
-
content: [{ type: "text", text: message }],
|
|
789
|
-
isError: isError
|
|
790
|
-
};
|
|
791
|
-
}
|
|
792
|
-
catch (e) {
|
|
793
|
-
console.error(`Error compile_project ${absPath}: ${e}`);
|
|
794
|
-
return {
|
|
795
|
-
content: [{ type: "text", text: `Error: ${e.message}` }],
|
|
796
|
-
isError: true
|
|
797
|
-
};
|
|
798
|
-
}
|
|
799
|
-
}));
|
|
800
|
-
// --- Session Management Tools ---
|
|
801
|
-
server.tool("start_session", "Starts a persistent CODESYS session for improved performance with multiple operations", {}, () => __awaiter(this, void 0, void 0, function* () {
|
|
802
|
-
console.error("Tool call: start_session");
|
|
803
|
-
// First check if session manager is defined
|
|
804
|
-
if (!sessionManager) {
|
|
805
|
-
console.error("Tool call: start_session - session manager is not defined");
|
|
806
|
-
return {
|
|
807
|
-
content: [{
|
|
808
|
-
type: "text",
|
|
809
|
-
text: "Session management is disabled. Use the toolkit without the --no-session flag to enable session management."
|
|
810
|
-
}],
|
|
811
|
-
isError: true
|
|
812
|
-
};
|
|
813
|
-
}
|
|
814
|
-
try {
|
|
815
|
-
const currentState = sessionManager.getState();
|
|
816
|
-
if (currentState === sessionManager_1.SessionState.RUNNING || currentState === sessionManager_1.SessionState.BUSY) {
|
|
817
|
-
return {
|
|
818
|
-
content: [{
|
|
819
|
-
type: "text",
|
|
820
|
-
text: "CODESYS session is already running"
|
|
821
|
-
}],
|
|
822
|
-
isError: false
|
|
823
|
-
};
|
|
824
|
-
}
|
|
825
|
-
if (currentState === sessionManager_1.SessionState.STARTING) {
|
|
826
|
-
return {
|
|
827
|
-
content: [{
|
|
828
|
-
type: "text",
|
|
829
|
-
text: "CODESYS session is already starting"
|
|
830
|
-
}],
|
|
831
|
-
isError: false
|
|
832
|
-
};
|
|
833
|
-
}
|
|
834
|
-
yield sessionManager.startSession();
|
|
835
|
-
return {
|
|
836
|
-
content: [{
|
|
837
|
-
type: "text",
|
|
838
|
-
text: "CODESYS session started successfully"
|
|
839
|
-
}],
|
|
840
|
-
isError: false
|
|
841
|
-
};
|
|
842
|
-
}
|
|
843
|
-
catch (error) {
|
|
844
|
-
console.error(`Error starting session: ${error.message}`);
|
|
845
|
-
return {
|
|
846
|
-
content: [{
|
|
847
|
-
type: "text",
|
|
848
|
-
text: `Failed to start CODESYS session: ${error.message}`
|
|
849
|
-
}],
|
|
850
|
-
isError: true
|
|
851
|
-
};
|
|
852
|
-
}
|
|
853
|
-
}));
|
|
854
|
-
server.tool("stop_session", "Stops the persistent CODESYS session", {}, () => __awaiter(this, void 0, void 0, function* () {
|
|
855
|
-
console.error("Tool call: stop_session");
|
|
856
|
-
// First check if session manager is defined
|
|
857
|
-
if (!sessionManager) {
|
|
858
|
-
console.error("Tool call: stop_session - session manager is not defined");
|
|
859
|
-
return {
|
|
860
|
-
content: [{
|
|
861
|
-
type: "text",
|
|
862
|
-
text: "Session management is disabled. No active session to stop."
|
|
863
|
-
}],
|
|
864
|
-
isError: false // Not an error, as there's no session to stop
|
|
865
|
-
};
|
|
866
|
-
}
|
|
867
|
-
try {
|
|
868
|
-
const currentState = sessionManager.getState();
|
|
869
|
-
if (currentState === sessionManager_1.SessionState.STOPPED) {
|
|
870
|
-
return {
|
|
871
|
-
content: [{
|
|
872
|
-
type: "text",
|
|
873
|
-
text: "CODESYS session is already stopped"
|
|
874
|
-
}],
|
|
875
|
-
isError: false
|
|
876
|
-
};
|
|
877
|
-
}
|
|
878
|
-
if (currentState === sessionManager_1.SessionState.STOPPING) {
|
|
879
|
-
return {
|
|
880
|
-
content: [{
|
|
881
|
-
type: "text",
|
|
882
|
-
text: "CODESYS session is already stopping"
|
|
883
|
-
}],
|
|
884
|
-
isError: false
|
|
885
|
-
};
|
|
886
|
-
}
|
|
887
|
-
yield sessionManager.stopSession();
|
|
888
|
-
return {
|
|
889
|
-
content: [{
|
|
890
|
-
type: "text",
|
|
891
|
-
text: "CODESYS session stopped successfully"
|
|
892
|
-
}],
|
|
893
|
-
isError: false
|
|
894
|
-
};
|
|
895
|
-
}
|
|
896
|
-
catch (error) {
|
|
897
|
-
console.error(`Error stopping session: ${error.message}`);
|
|
898
|
-
return {
|
|
899
|
-
content: [{
|
|
900
|
-
type: "text",
|
|
901
|
-
text: `Failed to stop CODESYS session: ${error.message}`
|
|
902
|
-
}],
|
|
903
|
-
isError: true
|
|
904
|
-
};
|
|
905
|
-
}
|
|
906
|
-
}));
|
|
907
|
-
server.tool("session_status", "Returns the status of the CODESYS session", {}, () => __awaiter(this, void 0, void 0, function* () {
|
|
908
|
-
console.error("Tool call: session_status");
|
|
909
|
-
// First check if session manager is defined
|
|
910
|
-
if (!sessionManager) {
|
|
911
|
-
console.error("Tool call: session_status - session manager is not defined");
|
|
912
|
-
return {
|
|
913
|
-
content: [{
|
|
914
|
-
type: "text",
|
|
915
|
-
text: "Session management is disabled. Status: DISABLED"
|
|
916
|
-
}],
|
|
917
|
-
isError: false
|
|
918
|
-
};
|
|
919
|
-
}
|
|
920
|
-
try {
|
|
921
|
-
const state = sessionManager.getState();
|
|
922
|
-
return {
|
|
923
|
-
content: [{
|
|
924
|
-
type: "text",
|
|
925
|
-
text: `CODESYS session status: ${state}`
|
|
926
|
-
}],
|
|
927
|
-
isError: false
|
|
928
|
-
};
|
|
929
|
-
}
|
|
930
|
-
catch (error) {
|
|
931
|
-
console.error(`Error getting session status: ${error.message}`);
|
|
932
|
-
return {
|
|
933
|
-
content: [{
|
|
934
|
-
type: "text",
|
|
935
|
-
text: `Failed to get CODESYS session status: ${error.message}`
|
|
936
|
-
}],
|
|
937
|
-
isError: true
|
|
938
|
-
};
|
|
939
|
-
}
|
|
940
|
-
}));
|
|
941
|
-
// --- End Tools ---
|
|
942
|
-
console.error("SERVER.TS: Resources and Tools defined.");
|
|
943
|
-
// --- End MCP Resources / Tools Definitions ---
|
|
944
|
-
// --- Server Connection ---
|
|
945
|
-
console.error("SERVER.TS: startServer() internal logic executing.");
|
|
946
|
-
try {
|
|
947
|
-
const transport = new stdio_js_1.StdioServerTransport();
|
|
948
|
-
console.error("SERVER.TS: Connecting MCP server via stdio...");
|
|
949
|
-
// No need to await connect here if startMcpServer is called by bin.ts which awaits it
|
|
950
|
-
server.connect(transport); // Connect but don't await here, let bin.ts handle waiting
|
|
951
|
-
console.error("SERVER.TS: MCP Server connection initiated via stdio.");
|
|
952
|
-
}
|
|
953
|
-
catch (error) {
|
|
954
|
-
console.error("FATAL: Failed to initiate MCP server connection:", error);
|
|
955
|
-
// Re-throw error so bin.ts can catch it
|
|
956
|
-
throw error;
|
|
957
|
-
}
|
|
958
|
-
// --- End Server Connection ---
|
|
959
|
-
});
|
|
960
|
-
} // --- End of startMcpServer function ---
|
|
961
|
-
// --- Graceful Shutdown / Unhandled Rejection ---
|
|
962
|
-
// These should remain at the top level, outside startMcpServer
|
|
963
|
-
process.on('SIGINT', () => {
|
|
964
|
-
console.error('\nSERVER.TS: SIGINT received, shutting down...');
|
|
965
|
-
process.exit(0);
|
|
966
|
-
});
|
|
967
|
-
process.on('SIGTERM', () => {
|
|
968
|
-
console.error('\nSERVER.TS: SIGTERM received, shutting down...');
|
|
969
|
-
process.exit(0);
|
|
970
|
-
});
|
|
971
|
-
process.on('unhandledRejection', (reason, promise) => {
|
|
972
|
-
console.error('SERVER.TS: Unhandled Rejection at:', promise, 'reason:', reason);
|
|
973
|
-
});
|
|
974
|
-
// --- End Graceful Shutdown / Unhandled Rejection ---
|
|
975
|
-
console.error(">>> SERVER.TS Module Parsed <<<"); // Log end of script parsing
|
|
32
|
+
return server;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=server.js.map
|