From 33f494e5ad6bf353541c554f3110a3c223603f50 Mon Sep 17 00:00:00 2001 From: Karstein Phobic Nyvold Kvistad Date: Sat, 25 Apr 2026 16:47:08 +0200 Subject: [PATCH] fix(install_addon_from_file): correct default --location and document elevation Two issues found while installing CODESYS Control for PFC200 SL 4.20.0.0 on the test machine: 1) Default --location derivation was off by one dirname. APInstaller wants the CODESYS install root (the directory containing Common\CODESYS.exe), not its parent. The original derivation (path.dirname x3 from config.codesysPath) gave the parent 'C:\Program Files\CODESYS 3.5.XX.YY', which APInstaller rejects: Error: No installation was found in the directory ... Corrected to (path.dirname x2) which gives the install root 'C:\Program Files\CODESYS 3.5.XX.YY\CODESYS'. Confirmed by re-running with the explicit installation arg pointing there: APInstaller stopped with the elevation error instead, meaning it reached the install. 2) APInstaller writes under Program Files and so requires admin rights. Without them it exits code 1 with: Error: This command needs elevated rights to run. The MCP server runs at user level by default, so this is not something the tool itself can fix -- the MCP server must be launched elevated for this tool to work. Documented in the tool description so the failure mode is no longer surprising. The companion tool description for the 'installation' arg was also updated to clarify it expects the install root, not the parent. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/server.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/server.ts b/src/server.ts index a4110d1..62e9206 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1118,10 +1118,10 @@ export async function startMcpServer(config: ServerConfig): Promise { s.tool( 'install_addon_from_file', - "Installs a CODESYS .package add-on (e.g. WAGO PFC libraries bundle, vendor packages) into a CODESYS installation by shelling out to APInstaller.CLI.exe --installAddOnFromFile. Use this for .package bundles; use install_library_file for plain .library files. Does not need CODESYS UI to be running.", + "Installs a CODESYS .package add-on (e.g. WAGO PFC libraries bundle, vendor packages) into a CODESYS installation by shelling out to APInstaller.CLI.exe --installAddOnFromFile. Use this for .package bundles; use install_library_file for plain .library files. Does not need CODESYS UI to be running. NOTE: writes under C:\\Program Files\\CODESYS\\... so requires admin rights -- the MCP server itself must have been launched elevated, otherwise APInstaller exits with 'This command needs elevated rights to run.'", { packageFilePath: z.string().describe("Full path to the .package file to install."), - installation: z.string().optional().describe("Installation location (e.g. 'C:\\\\Program Files\\\\CODESYS 3.5.21.50'). Defaults to the parent of this MCP's configured CODESYS install."), + installation: z.string().optional().describe("CODESYS install root (e.g. 'C:\\\\Program Files\\\\CODESYS 3.5.21.50\\\\CODESYS' -- the directory containing Common\\\\CODESYS.exe). Defaults to the install root derived from this MCP's configured CODESYS path."), }, async (args: { packageFilePath: string; installation?: string }) => { const cli = locateAPInstallerCli(); @@ -1141,9 +1141,13 @@ export async function startMcpServer(config: ServerConfig): Promise { isError: true, }; } - // Default installation location = parent of CODESYS\Common\CODESYS.exe - // i.e. three dirnames up from config.codesysPath - const defaultLocation = path.dirname(path.dirname(path.dirname(config.codesysPath))); + // Default installation location = the CODESYS install root, i.e. + // C:\Program Files\CODESYS 3.5.XX.YY\CODESYS. config.codesysPath + // points at ...\CODESYS\Common\CODESYS.exe, so two dirnames up. + // (APInstaller --location wants this exact directory; the parent + // 'C:\Program Files\CODESYS 3.5.XX.YY' is rejected with + // "No installation was found in the directory ...".) + const defaultLocation = path.dirname(path.dirname(config.codesysPath)); const location = args.installation && args.installation.trim().length > 0 ? path.normalize(args.installation) : defaultLocation;