genexus-mcp 3.7.0 → 3.7.2
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/cli/commands/axi.js +9 -4
- package/cli/run.test.js +167 -24
- package/cli/test-support/home-write-guard.js +66 -0
- package/package.json +1 -1
- package/publish/GxMcp.Gateway.deps.json +2 -2
- package/publish/GxMcp.Gateway.dll +0 -0
- package/publish/GxMcp.Gateway.exe +0 -0
- package/publish/config.json +9 -9
- package/publish/gxmcp-manifest.json +10 -10
- package/publish/gxmcp-sbom.json +4 -4
- package/publish/state/mutation-recovery.json.lock +0 -0
- package/publish/tool_definitions.json +6 -6
- package/publish/worker/GxMcp.Worker.exe +0 -0
package/cli/commands/axi.js
CHANGED
|
@@ -454,6 +454,13 @@ function resolveMcpSmokeTarget(cwd) {
|
|
|
454
454
|
return { applicable: true, status: null, detail: null, baseUrl: `http://${host}:${port}/mcp` };
|
|
455
455
|
}
|
|
456
456
|
|
|
457
|
+
function buildMcpSmokeCommand(scriptPath, baseUrl) {
|
|
458
|
+
return {
|
|
459
|
+
shell: 'pwsh',
|
|
460
|
+
args: ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', scriptPath, '-BaseUrl', baseUrl]
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
|
|
457
464
|
async function runMcpSmokeProbe(cwd) {
|
|
458
465
|
const scriptPath = path.join(__dirname, '..', '..', 'scripts', 'mcp_smoke.ps1');
|
|
459
466
|
if (!fs.existsSync(scriptPath)) {
|
|
@@ -465,10 +472,7 @@ async function runMcpSmokeProbe(cwd) {
|
|
|
465
472
|
return { status: target.status, detail: target.detail };
|
|
466
473
|
}
|
|
467
474
|
const baseUrl = target.baseUrl;
|
|
468
|
-
const shell
|
|
469
|
-
const args = process.platform === 'win32'
|
|
470
|
-
? ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', scriptPath, '-BaseUrl', baseUrl]
|
|
471
|
-
: ['-NoProfile', '-File', scriptPath, '-BaseUrl', baseUrl];
|
|
475
|
+
const { shell, args } = buildMcpSmokeCommand(scriptPath, baseUrl);
|
|
472
476
|
|
|
473
477
|
return await new Promise((resolve) => {
|
|
474
478
|
let stdout = '';
|
|
@@ -3053,5 +3057,6 @@ module.exports = {
|
|
|
3053
3057
|
usageEnvelope,
|
|
3054
3058
|
operationalErrorEnvelope,
|
|
3055
3059
|
resolveMcpSmokeTarget,
|
|
3060
|
+
buildMcpSmokeCommand,
|
|
3056
3061
|
commandHelpMap
|
|
3057
3062
|
};
|
package/cli/run.test.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
const test = require('node:test');
|
|
2
2
|
const assert = require('node:assert/strict');
|
|
3
|
-
const { spawnSync } = require('node:child_process');
|
|
3
|
+
const { spawn, spawnSync } = require('node:child_process');
|
|
4
4
|
const { Readable, Writable } = require('node:stream');
|
|
5
5
|
const path = require('node:path');
|
|
6
6
|
const os = require('node:os');
|
|
7
7
|
const fs = require('node:fs');
|
|
8
|
+
const { protectedRoots } = require('./test-support/home-write-guard');
|
|
8
9
|
const { renderOutput } = require('./lib/output');
|
|
9
10
|
const {
|
|
10
11
|
compareSemver,
|
|
@@ -29,7 +30,7 @@ const {
|
|
|
29
30
|
switchActiveKb,
|
|
30
31
|
patchClientConfig
|
|
31
32
|
} = require('./lib/config');
|
|
32
|
-
const { handleInit, resolveMcpSmokeTarget } = require('./commands/axi');
|
|
33
|
+
const { handleInit, resolveMcpSmokeTarget, buildMcpSmokeCommand } = require('./commands/axi');
|
|
33
34
|
|
|
34
35
|
const cliPath = path.join(__dirname, 'run.js');
|
|
35
36
|
const testGxPath = fs.mkdtempSync(path.join(os.tmpdir(), 'genexus-mcp-gx-'));
|
|
@@ -68,23 +69,29 @@ function removeTempPath(targetPath, options = {}, deps = {}) {
|
|
|
68
69
|
}
|
|
69
70
|
}
|
|
70
71
|
|
|
71
|
-
// Issue #211 teardown safety net: a probe child that outlives its terminate
|
|
72
|
+
// Issue #211/#248 teardown safety net: a probe child that outlives its terminate
|
|
72
73
|
// signal keeps the stubbed GxMcp.Gateway.exe image mapped, which turns the
|
|
73
74
|
// cleanup rmSync into EPERM. Terminate only processes started from this test's
|
|
74
75
|
// own temp dir — never a machine-wide GxMcp.Gateway.exe sweep, which would hit
|
|
75
76
|
// other checkouts and the operator's own gateways.
|
|
76
77
|
function stopLingeringGatewayStubs(dirPath, deps = {}) {
|
|
77
78
|
const platform = deps.platform || process.platform;
|
|
78
|
-
const run = deps.run || ((command, args) => spawnSync(command, args, {
|
|
79
|
+
const run = deps.run || ((command, args) => spawnSync(command, args, {
|
|
80
|
+
encoding: 'utf8',
|
|
81
|
+
windowsHide: true,
|
|
82
|
+
timeout: 20000
|
|
83
|
+
}));
|
|
79
84
|
if (platform !== 'win32') return false;
|
|
80
85
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
86
|
+
let canonicalDir = String(dirPath);
|
|
87
|
+
try { canonicalDir = fs.realpathSync.native(canonicalDir); } catch { }
|
|
88
|
+
const escapedDir = canonicalDir.replace(/'/g, "''");
|
|
89
|
+
const processPipeline = [
|
|
84
90
|
`Get-CimInstance Win32_Process -Filter "Name = 'GxMcp.Gateway.exe'"`,
|
|
85
|
-
|
|
86
|
-
'ForEach-Object { Stop-Process -Id $
|
|
91
|
+
'Where-Object { if (-not $_.ExecutablePath -or -not $targetDirectory) { return $false }; $processDirectory = (Get-Item -LiteralPath ([System.IO.Path]::GetDirectoryName($_.ExecutablePath)) -ErrorAction SilentlyContinue).FullName; $processDirectory -and [System.StringComparer]::OrdinalIgnoreCase.Equals($processDirectory, $targetDirectory) }',
|
|
92
|
+
'ForEach-Object { $processId = $_.ProcessId; Stop-Process -Id $processId -Force; try { Wait-Process -Id $processId -Timeout 5 -ErrorAction SilentlyContinue } catch { } }'
|
|
87
93
|
].join(' | ');
|
|
94
|
+
const script = `$ErrorActionPreference = 'SilentlyContinue'; $targetDirectory = (Get-Item -LiteralPath '${escapedDir}' -ErrorAction SilentlyContinue).FullName; ${processPipeline}`;
|
|
88
95
|
try {
|
|
89
96
|
run('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', script]);
|
|
90
97
|
} catch { }
|
|
@@ -92,20 +99,82 @@ function stopLingeringGatewayStubs(dirPath, deps = {}) {
|
|
|
92
99
|
}
|
|
93
100
|
|
|
94
101
|
test.after(() => {
|
|
95
|
-
removeTempPath(testGxPath, { recursive: true, force: true });
|
|
96
102
|
stopLingeringGatewayStubs(testGatewayDir);
|
|
97
|
-
|
|
103
|
+
let firstError = null;
|
|
104
|
+
for (const directory of [testGxPath, testGatewayDir]) {
|
|
105
|
+
try {
|
|
106
|
+
removeTempPath(directory, { recursive: true, force: true });
|
|
107
|
+
} catch (error) {
|
|
108
|
+
if (!firstError) firstError = error;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (firstError) throw firstError;
|
|
98
112
|
});
|
|
99
113
|
|
|
114
|
+
// init/uninstall must never patch the operator's clients or ~/.genexus-mcp.
|
|
115
|
+
// Explicit fixture homes override this suite sandbox without changing the parent env.
|
|
116
|
+
const cliHome = fs.mkdtempSync(path.join(os.tmpdir(), 'genexus-mcp-cli-home-'));
|
|
117
|
+
test.after(() => removeTempPath(cliHome, { recursive: true, force: true }));
|
|
118
|
+
|
|
100
119
|
function runCli(args, opts = {}) {
|
|
101
120
|
const spawnOptions = {
|
|
102
121
|
encoding: 'utf8',
|
|
103
122
|
cwd: opts.cwd || process.cwd(),
|
|
104
|
-
env: {
|
|
123
|
+
env: {
|
|
124
|
+
...process.env, ...sandboxHomeEnv(fs.mkdtempSync(path.join(cliHome, 'case-'))),
|
|
125
|
+
GX_CONFIG_PATH: '', GENEXUS_MCP_GATEWAY_EXE: '', GENEXUS_HOME: '', NODE_OPTIONS: '',
|
|
126
|
+
GENEXUS_MCP_NO_UPDATE_CHECK: '1', ...(opts.env || {}),
|
|
127
|
+
GXMCP_TEST_PROTECTED_ROOTS: JSON.stringify(protectedRoots)
|
|
128
|
+
}
|
|
105
129
|
};
|
|
106
|
-
return spawnSync(process.execPath, [cliPath, ...args], spawnOptions);
|
|
130
|
+
return spawnSync(process.execPath, ['--require', path.join(__dirname, 'test-support/home-write-guard.js'), cliPath, ...args], spawnOptions);
|
|
107
131
|
}
|
|
108
132
|
|
|
133
|
+
test('home write guard stops mutation before backup and cannot be swallowed', () => {
|
|
134
|
+
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'genexus-mcp-guard-'));
|
|
135
|
+
const operatorConfig = path.join(tempRoot, 'operator', '.cursor', 'mcp.json');
|
|
136
|
+
fs.mkdirSync(path.dirname(operatorConfig), { recursive: true });
|
|
137
|
+
fs.writeFileSync(operatorConfig, '{"mcpServers":{"keep":{}}}');
|
|
138
|
+
try {
|
|
139
|
+
const guard = path.join(__dirname, 'test-support/home-write-guard.js');
|
|
140
|
+
const launcherDir = path.join(tempRoot, 'operator', '.genexus-mcp');
|
|
141
|
+
const claudeConfig = path.join(tempRoot, 'operator', '.claude.json');
|
|
142
|
+
const env = { ...process.env, ...sandboxHomeEnv(path.join(tempRoot, 'operator')),
|
|
143
|
+
GENEXUS_MCP_GATEWAY_EXE: '', NODE_OPTIONS: '',
|
|
144
|
+
GXMCP_TEST_PROTECTED_ROOTS: JSON.stringify([path.dirname(operatorConfig), launcherDir, claudeConfig]) };
|
|
145
|
+
const script = `try { require(${JSON.stringify(path.join(__dirname, 'lib/config.js'))}).patchClientConfig('fixture.json', { ids: ['cursor'], onlyExisting: false }); } catch {} process.exit(0);`;
|
|
146
|
+
const result = spawnSync(process.execPath, ['--require', guard, '-e', script], { env, encoding: 'utf8' });
|
|
147
|
+
assert.equal(result.status, 97, result.stderr);
|
|
148
|
+
assert.match(result.stderr, /GXMCP_TEST_HOME_WRITE_BLOCKED/);
|
|
149
|
+
assert.equal(fs.readFileSync(operatorConfig, 'utf8'), '{"mcpServers":{"keep":{}}}');
|
|
150
|
+
assert.deepEqual(fs.readdirSync(path.dirname(operatorConfig)), ['mcp.json']);
|
|
151
|
+
|
|
152
|
+
// Exercise launcher writes and atomic/backup paths independently of client detection.
|
|
153
|
+
for (const operation of [
|
|
154
|
+
`writeFileSync(${JSON.stringify(operatorConfig + '.tmp-test')}, 'bad')`,
|
|
155
|
+
`copyFileSync(${JSON.stringify(operatorConfig)}, ${JSON.stringify(operatorConfig + '.bak')})`,
|
|
156
|
+
`unlinkSync(${JSON.stringify(operatorConfig)})`,
|
|
157
|
+
`openSync(${JSON.stringify(operatorConfig)}, 'w')`,
|
|
158
|
+
`mkdirSync(${JSON.stringify(launcherDir)}, { recursive: true })`,
|
|
159
|
+
`writeFileSync(${JSON.stringify(claudeConfig + '.20260921.bak')}, 'bad')`
|
|
160
|
+
]) {
|
|
161
|
+
const denied = spawnSync(process.execPath, ['--require', guard, '-e',
|
|
162
|
+
`try { require('node:fs').${operation}; } catch {} process.exit(0);`], { env, encoding: 'utf8' });
|
|
163
|
+
assert.equal(denied.status, 97, operation + denied.stderr);
|
|
164
|
+
}
|
|
165
|
+
assert.equal(fs.readFileSync(operatorConfig, 'utf8'), '{"mcpServers":{"keep":{}}}');
|
|
166
|
+
assert.deepEqual(fs.readdirSync(path.dirname(operatorConfig)), ['mcp.json']);
|
|
167
|
+
assert.equal(fs.existsSync(launcherDir), false);
|
|
168
|
+
assert.equal(fs.existsSync(claudeConfig + '.20260921.bak'), false);
|
|
169
|
+
|
|
170
|
+
const fixture = path.join(tempRoot, 'fixture.json');
|
|
171
|
+
const allowed = spawnSync(process.execPath, ['--require', guard, '-e',
|
|
172
|
+
`require('node:fs').writeFileSync(${JSON.stringify(fixture)}, 'ok')`], { env, encoding: 'utf8' });
|
|
173
|
+
assert.equal(allowed.status, 0, allowed.stderr);
|
|
174
|
+
assert.equal(fs.readFileSync(fixture, 'utf8'), 'ok');
|
|
175
|
+
} finally { removeTempPath(tempRoot, { recursive: true, force: true }); }
|
|
176
|
+
});
|
|
177
|
+
|
|
109
178
|
test('temporary cleanup retries transient Windows removal errors', () => {
|
|
110
179
|
let attempts = 0;
|
|
111
180
|
const sleeps = [];
|
|
@@ -176,11 +245,66 @@ test('lingering gateway stub cleanup stays scoped to the test temp dir', () => {
|
|
|
176
245
|
assert.equal(windowsCalls[0][0], 'powershell.exe');
|
|
177
246
|
|
|
178
247
|
const script = windowsCalls[0][1].join(' ');
|
|
248
|
+
assert.ok(script.includes("'SilentlyContinue'; $targetDirectory") && script.includes('; Get-CimInstance'), 'must set PowerShell error handling before starting the process pipeline');
|
|
179
249
|
assert.ok(script.includes("GxMcp.Gateway.exe"), 'must target the stubbed gateway image');
|
|
180
250
|
assert.ok(script.includes('C:\\Temp\\genexus-mcp-test-1'), 'must be scoped to the test temp dir');
|
|
251
|
+
assert.ok(script.includes('Wait-Process -Id $processId -Timeout 5'), 'must wait for targeted processes to exit before removing the temp directory');
|
|
181
252
|
assert.ok(!script.includes('Stop-Process -Name'), 'must never terminate by process name machine-wide');
|
|
182
253
|
});
|
|
183
254
|
|
|
255
|
+
test('lingering gateway stub cleanup escapes PowerShell path literals', () => {
|
|
256
|
+
const calls = [];
|
|
257
|
+
stopLingeringGatewayStubs("C:\\Temp\\o'brien", {
|
|
258
|
+
platform: 'win32',
|
|
259
|
+
run: (_command, args) => calls.push(args.join(' '))
|
|
260
|
+
});
|
|
261
|
+
assert.equal(calls.length, 1);
|
|
262
|
+
assert.ok(calls[0].includes("C:\\Temp\\o''brien"), 'single quotes must be doubled inside the PowerShell literal');
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
function waitForChildExit(child, timeoutMs = 10000) {
|
|
266
|
+
return new Promise((resolve) => {
|
|
267
|
+
if (!child || child.exitCode !== null || child.signalCode !== null) {
|
|
268
|
+
resolve(true);
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
const timer = setTimeout(() => resolve(false), timeoutMs);
|
|
272
|
+
child.once('exit', () => {
|
|
273
|
+
clearTimeout(timer);
|
|
274
|
+
resolve(true);
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
test('windows cleanup stops a real scoped gateway stub before removal', { skip: process.platform !== 'win32' }, async () => {
|
|
280
|
+
const probeDir = path.join(testGatewayDir, 'wait-probe');
|
|
281
|
+
const probePath = path.join(probeDir, 'GxMcp.Gateway.exe');
|
|
282
|
+
fs.mkdirSync(probeDir, { recursive: true });
|
|
283
|
+
fs.copyFileSync(testGatewayPath, probePath);
|
|
284
|
+
const child = spawn(probePath, ['/c', 'ping 127.0.0.1 -n 5 > nul'], {
|
|
285
|
+
stdio: 'ignore',
|
|
286
|
+
windowsHide: true
|
|
287
|
+
});
|
|
288
|
+
await new Promise((resolve, reject) => {
|
|
289
|
+
child.once('spawn', resolve);
|
|
290
|
+
child.once('error', reject);
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
stopLingeringGatewayStubs(probeDir);
|
|
294
|
+
let removeError = null;
|
|
295
|
+
try {
|
|
296
|
+
fs.rmSync(probeDir, { recursive: true, force: true });
|
|
297
|
+
} catch (error) {
|
|
298
|
+
removeError = error;
|
|
299
|
+
}
|
|
300
|
+
const exited = await waitForChildExit(child);
|
|
301
|
+
if (!exited) {
|
|
302
|
+
try { child.kill(); } catch { }
|
|
303
|
+
}
|
|
304
|
+
assert.equal(removeError, null, `the scoped cleanup must release the gateway image before removal: ${removeError?.message || removeError}`);
|
|
305
|
+
assert.equal(exited, true, 'the scoped cleanup must terminate the gateway stub before directory removal');
|
|
306
|
+
});
|
|
307
|
+
|
|
184
308
|
test('a failed stub cleanup does not mask the test result', () => {
|
|
185
309
|
const ran = stopLingeringGatewayStubs('C:\\Temp\\genexus-mcp-test-1', {
|
|
186
310
|
platform: 'win32',
|
|
@@ -1371,6 +1495,13 @@ test('doctor marks HTTP smoke not applicable for stdio-isolated runtime', () =>
|
|
|
1371
1495
|
}
|
|
1372
1496
|
});
|
|
1373
1497
|
|
|
1498
|
+
test('doctor MCP smoke uses the PowerShell 7 host', () => {
|
|
1499
|
+
const command = buildMcpSmokeCommand(path.join('repo', 'scripts', 'mcp_smoke.ps1'), 'http://127.0.0.1:5000/mcp');
|
|
1500
|
+
assert.equal(command.shell, 'pwsh');
|
|
1501
|
+
assert.deepEqual(command.args.slice(0, 3), ['-NoProfile', '-ExecutionPolicy', 'Bypass']);
|
|
1502
|
+
assert.ok(command.args.some((arg) => arg.endsWith('mcp_smoke.ps1')));
|
|
1503
|
+
});
|
|
1504
|
+
|
|
1374
1505
|
test('doctor reports a KB and SDK major mismatch', () => {
|
|
1375
1506
|
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'genexus-mcp-doctor-major-'));
|
|
1376
1507
|
const kbDir = path.join(tempRoot, 'kb17');
|
|
@@ -1631,6 +1762,8 @@ function sandboxHomeEnv(root) {
|
|
|
1631
1762
|
}
|
|
1632
1763
|
|
|
1633
1764
|
test('clients list returns structured status with summary', () => {
|
|
1765
|
+
const parentHome = sandboxHomeEnv('unused');
|
|
1766
|
+
for (const key of Object.keys(parentHome)) parentHome[key] = process.env[key];
|
|
1634
1767
|
const result = runCli(['clients', '--format', 'json']);
|
|
1635
1768
|
assert.equal(result.status, 0);
|
|
1636
1769
|
const parsed = JSON.parse(result.stdout);
|
|
@@ -1643,6 +1776,10 @@ test('clients list returns structured status with summary', () => {
|
|
|
1643
1776
|
assert.ok(row, 'antigravity should be listed');
|
|
1644
1777
|
assert.equal(typeof row.installed, 'boolean');
|
|
1645
1778
|
assert.equal(typeof row.registered, 'boolean');
|
|
1779
|
+
for (const client of parsed.ok.clients) {
|
|
1780
|
+
assert.ok(client.configPath.startsWith(cliHome + path.sep), client.configPath);
|
|
1781
|
+
}
|
|
1782
|
+
for (const [key, value] of Object.entries(parentHome)) assert.equal(process.env[key], value);
|
|
1646
1783
|
});
|
|
1647
1784
|
|
|
1648
1785
|
test('clients list reports OpenCode Desktop with shared opencode config', () => {
|
|
@@ -2834,11 +2971,17 @@ function fsFailureProxy(realFs, failure) {
|
|
|
2834
2971
|
});
|
|
2835
2972
|
}
|
|
2836
2973
|
|
|
2837
|
-
function patchFailureFixture(prefix) {
|
|
2974
|
+
function patchFailureFixture(prefix, t) {
|
|
2838
2975
|
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), prefix));
|
|
2839
2976
|
const env = sandboxHomeEnv(tempRoot);
|
|
2840
|
-
|
|
2841
|
-
|
|
2977
|
+
const previous = Object.fromEntries(Object.keys(env).map(key => [key, process.env[key]]));
|
|
2978
|
+
t.after(() => {
|
|
2979
|
+
for (const [key, value] of Object.entries(previous)) {
|
|
2980
|
+
if (value === undefined) delete process.env[key];
|
|
2981
|
+
else process.env[key] = value;
|
|
2982
|
+
}
|
|
2983
|
+
});
|
|
2984
|
+
Object.assign(process.env, env);
|
|
2842
2985
|
const cfgPath = path.join(tempRoot, 'config.json');
|
|
2843
2986
|
fs.writeFileSync(cfgPath, JSON.stringify({ Environment: { KBPath: tempRoot } }));
|
|
2844
2987
|
const openCodeCfg = path.join(env.XDG_CONFIG_HOME, 'opencode', 'opencode.json');
|
|
@@ -2850,8 +2993,8 @@ function patchFailureFixture(prefix) {
|
|
|
2850
2993
|
return { tempRoot, env, cfgPath, openCodeCfg, vscodeCfg };
|
|
2851
2994
|
}
|
|
2852
2995
|
|
|
2853
|
-
test('patchClientConfig reports backup failure without claiming that client patched', () => {
|
|
2854
|
-
const fixture = patchFailureFixture('genexus-mcp-partial-backup-');
|
|
2996
|
+
test('patchClientConfig reports backup failure without claiming that client patched', (t) => {
|
|
2997
|
+
const fixture = patchFailureFixture('genexus-mcp-partial-backup-', t);
|
|
2855
2998
|
try {
|
|
2856
2999
|
const result = patchClientConfig(fixture.cfgPath, {
|
|
2857
3000
|
ids: ['opencode', 'vscode'], onlyExisting: false,
|
|
@@ -2864,8 +3007,8 @@ test('patchClientConfig reports backup failure without claiming that client patc
|
|
|
2864
3007
|
} finally { removeTempPath(fixture.tempRoot, { recursive: true, force: true }); }
|
|
2865
3008
|
});
|
|
2866
3009
|
|
|
2867
|
-
test('patchClientConfig preserves earlier success when a later client write fails', () => {
|
|
2868
|
-
const fixture = patchFailureFixture('genexus-mcp-partial-write-');
|
|
3010
|
+
test('patchClientConfig preserves earlier success when a later client write fails', (t) => {
|
|
3011
|
+
const fixture = patchFailureFixture('genexus-mcp-partial-write-', t);
|
|
2869
3012
|
try {
|
|
2870
3013
|
const result = patchClientConfig(fixture.cfgPath, {
|
|
2871
3014
|
ids: ['opencode', 'vscode'], onlyExisting: false,
|
|
@@ -2878,8 +3021,8 @@ test('patchClientConfig preserves earlier success when a later client write fail
|
|
|
2878
3021
|
} finally { removeTempPath(fixture.tempRoot, { recursive: true, force: true }); }
|
|
2879
3022
|
});
|
|
2880
3023
|
|
|
2881
|
-
test('patchClientConfig reports post-write read-back failure as partial state', () => {
|
|
2882
|
-
const fixture = patchFailureFixture('genexus-mcp-partial-readback-');
|
|
3024
|
+
test('patchClientConfig reports post-write read-back failure as partial state', (t) => {
|
|
3025
|
+
const fixture = patchFailureFixture('genexus-mcp-partial-readback-', t);
|
|
2883
3026
|
try {
|
|
2884
3027
|
const result = patchClientConfig(fixture.cfgPath, {
|
|
2885
3028
|
ids: ['opencode', 'vscode'], onlyExisting: false,
|
|
@@ -2892,8 +3035,8 @@ test('patchClientConfig reports post-write read-back failure as partial state',
|
|
|
2892
3035
|
} finally { removeTempPath(fixture.tempRoot, { recursive: true, force: true }); }
|
|
2893
3036
|
});
|
|
2894
3037
|
|
|
2895
|
-
test('patchClientConfig keeps a stale same-second backup and writes a distinct backup', () => {
|
|
2896
|
-
const fixture = patchFailureFixture('genexus-mcp-stale-backup-');
|
|
3038
|
+
test('patchClientConfig keeps a stale same-second backup and writes a distinct backup', (t) => {
|
|
3039
|
+
const fixture = patchFailureFixture('genexus-mcp-stale-backup-', t);
|
|
2897
3040
|
try {
|
|
2898
3041
|
const stamp = new Date().toISOString().replace(/[-:T]/g, '').slice(0, 14);
|
|
2899
3042
|
const stale = `${fixture.openCodeCfg}.${stamp}.bak`;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Test-only preload: snapshot real registry roots before any sandbox overrides.
|
|
2
|
+
// Exit immediately: config writers catch IO errors and may otherwise report success.
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const os = require('node:os');
|
|
6
|
+
const { URL, fileURLToPath } = require('node:url');
|
|
7
|
+
const { getClientConfigTargets } = require('../lib/config');
|
|
8
|
+
|
|
9
|
+
const inheritedRoots = process.env.GXMCP_TEST_PROTECTED_ROOTS;
|
|
10
|
+
const roots = inheritedRoots ? JSON.parse(inheritedRoots) : [
|
|
11
|
+
...getClientConfigTargets().flatMap(client => [client.path, ...(client.alternatePaths || [])])
|
|
12
|
+
.map(p => path.dirname(p) === os.homedir() ? p : path.dirname(p)),
|
|
13
|
+
...[os.homedir(), process.env.HOME, process.env.USERPROFILE].filter(Boolean).map(p => path.join(p, '.genexus-mcp')),
|
|
14
|
+
path.join(process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local'), 'GenexusMCP')
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
function canonicalPath(value) {
|
|
18
|
+
let current = path.resolve(value instanceof URL ? fileURLToPath(value) : String(value));
|
|
19
|
+
const tail = [];
|
|
20
|
+
while (!fs.existsSync(current)) {
|
|
21
|
+
const parent = path.dirname(current);
|
|
22
|
+
if (parent === current) break;
|
|
23
|
+
tail.unshift(path.basename(current));
|
|
24
|
+
current = parent;
|
|
25
|
+
}
|
|
26
|
+
const resolved = path.join(fs.realpathSync.native(current), ...tail);
|
|
27
|
+
return process.platform === 'win32' ? resolved.toLowerCase() : resolved;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const protectedRoots = [...new Set(roots.map(canonicalPath))];
|
|
31
|
+
const originalExit = process.exit.bind(process);
|
|
32
|
+
|
|
33
|
+
function checkWrite(value) {
|
|
34
|
+
if (typeof value === 'number') return; // writable descriptors are guarded at open.
|
|
35
|
+
const candidate = canonicalPath(value);
|
|
36
|
+
if (protectedRoots.some(root => candidate === root || candidate.startsWith(root + path.sep)
|
|
37
|
+
|| candidate.startsWith(root + '.'))) {
|
|
38
|
+
fs.writeSync(2, 'GXMCP_TEST_HOME_WRITE_BLOCKED: use sandboxHomeEnv; refusing operator configuration mutation.\n');
|
|
39
|
+
originalExit(97);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Guard the filesystem primitives used by client backups, atomic config writes,
|
|
44
|
+
// unpatch and launcher config. Installed in both the runner and CLI children.
|
|
45
|
+
// Config writers currently use sync IO; extend this guard if they adopt async IO.
|
|
46
|
+
for (const [method, indexes] of Object.entries({
|
|
47
|
+
mkdirSync: [0], writeFileSync: [0], appendFileSync: [0], unlinkSync: [0], rmSync: [0],
|
|
48
|
+
rmdirSync: [0], copyFileSync: [1], cpSync: [1], renameSync: [0, 1], truncateSync: [0],
|
|
49
|
+
mkdtempSync: [0], symlinkSync: [1], linkSync: [0, 1], createWriteStream: [0]
|
|
50
|
+
})) {
|
|
51
|
+
const original = fs[method];
|
|
52
|
+
fs[method] = function (...args) {
|
|
53
|
+
for (const index of indexes) checkWrite(args[index]);
|
|
54
|
+
return original.apply(this, args);
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
const originalOpen = fs.openSync;
|
|
58
|
+
fs.openSync = function (file, flags, ...args) {
|
|
59
|
+
const writable = typeof flags === 'number'
|
|
60
|
+
? flags & (fs.constants.O_WRONLY | fs.constants.O_RDWR | fs.constants.O_CREAT | fs.constants.O_TRUNC | fs.constants.O_APPEND)
|
|
61
|
+
: /[wa+]/.test(flags);
|
|
62
|
+
if (writable) checkWrite(file);
|
|
63
|
+
return originalOpen.call(this, file, flags, ...args);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
module.exports = { protectedRoots };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "genexus-mcp",
|
|
3
|
-
"version": "3.7.
|
|
3
|
+
"version": "3.7.2",
|
|
4
4
|
"mcpName": "io.github.lennix1337/genexus",
|
|
5
5
|
"description": "GeneXus 16, GeneXus 17, GeneXus 18 MCP server with native SDK support; basic legacy compatibility for GeneXus Evolution 3, GeneXus Evolution 2, GeneXus Evolution 1, GeneXus 15, GeneXus 9.0, GeneXus 8.0 via com-gxpublic and dotnet-reflection drivers — read, edit, and analyze Knowledge Base objects directly from Claude, Cursor, and other AI agents over the Model Context Protocol.",
|
|
6
6
|
"keywords": [
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"targets": {
|
|
8
8
|
".NETCoreApp,Version=v10.0": {},
|
|
9
9
|
".NETCoreApp,Version=v10.0/win-x64": {
|
|
10
|
-
"GxMcp.Gateway/3.7.
|
|
10
|
+
"GxMcp.Gateway/3.7.2": {
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"Newtonsoft.Json": "13.0.3",
|
|
13
13
|
"System.Management": "10.0.5",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
}
|
|
67
67
|
},
|
|
68
68
|
"libraries": {
|
|
69
|
-
"GxMcp.Gateway/3.7.
|
|
69
|
+
"GxMcp.Gateway/3.7.2": {
|
|
70
70
|
"type": "project",
|
|
71
71
|
"serviceable": false,
|
|
72
72
|
"sha512": ""
|
|
Binary file
|
|
Binary file
|
package/publish/config.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"GatewayMode": "stdio-isolated",
|
|
3
|
-
"
|
|
3
|
+
"Environment": {
|
|
4
|
+
"ResolutionPolicy": "strict"
|
|
5
|
+
},
|
|
4
6
|
"GeneXus": {
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
+
"InstallationPath": "C:\\Program Files (x86)\\GeneXus\\GeneXus18",
|
|
8
|
+
"WorkerExecutable": "worker\\\\GxMcp.Worker.exe"
|
|
7
9
|
},
|
|
10
|
+
"ConfigSchemaVersion": 2,
|
|
8
11
|
"Server": {
|
|
9
|
-
"WorkerIdleTimeoutMinutes": 5,
|
|
10
12
|
"HttpPort": 0,
|
|
11
|
-
"TerseResponses": true,
|
|
12
13
|
"SessionIdleTimeoutMinutes": 10,
|
|
14
|
+
"TerseResponses": true,
|
|
13
15
|
"EmitStructuredContent": false,
|
|
14
|
-
"McpStdio": true
|
|
15
|
-
|
|
16
|
-
"Environment": {
|
|
17
|
-
"ResolutionPolicy": "strict"
|
|
16
|
+
"McpStdio": true,
|
|
17
|
+
"WorkerIdleTimeoutMinutes": 5
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "gxmcp-release-manifest/1",
|
|
3
|
-
"version": "3.7.
|
|
4
|
-
"sourceCommit": "
|
|
3
|
+
"version": "3.7.2",
|
|
4
|
+
"sourceCommit": "8bfec41e1fb31839fac72bd5696bf848285a194a",
|
|
5
5
|
"sourceCommitPolicy": "exact-tag",
|
|
6
|
-
"generatedAtUtc": "2026-09-
|
|
6
|
+
"generatedAtUtc": "2026-09-22T04:09:07.5291470Z",
|
|
7
7
|
"runtime": {
|
|
8
8
|
"gateway": "net10.0-windows",
|
|
9
9
|
"worker": "net48-x86",
|
|
@@ -15,28 +15,28 @@
|
|
|
15
15
|
"2026-07-28"
|
|
16
16
|
],
|
|
17
17
|
"schema": "tool_definitions.json",
|
|
18
|
-
"schemaSha256": "
|
|
18
|
+
"schemaSha256": "1ee0eefa9c32227a76bd6261040f651b06b6096029607f91c9386e064461bb9e",
|
|
19
19
|
"provenance": "gxmcp-sbom.json",
|
|
20
20
|
"artifacts": [
|
|
21
21
|
{
|
|
22
22
|
"path": "gxmcp-sbom.json",
|
|
23
23
|
"size": 590,
|
|
24
|
-
"sha256": "
|
|
24
|
+
"sha256": "b01c1f14b0a9ac521c63f26a1c176765e8293784a362581370b01c86fbd3fffc"
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
"path": "GxMcp.Gateway.exe",
|
|
28
28
|
"size": 162304,
|
|
29
|
-
"sha256": "
|
|
29
|
+
"sha256": "f9e1bbd84d47f15f53b51229f49ee02e9b166ebd827f379691731ee3ca39b32f"
|
|
30
30
|
},
|
|
31
31
|
{
|
|
32
32
|
"path": "tool_definitions.json",
|
|
33
|
-
"size":
|
|
34
|
-
"sha256": "
|
|
33
|
+
"size": 126649,
|
|
34
|
+
"sha256": "1ee0eefa9c32227a76bd6261040f651b06b6096029607f91c9386e064461bb9e"
|
|
35
35
|
},
|
|
36
36
|
{
|
|
37
37
|
"path": "worker/GxMcp.Worker.exe",
|
|
38
|
-
"size":
|
|
39
|
-
"sha256": "
|
|
38
|
+
"size": 3476992,
|
|
39
|
+
"sha256": "3ee2a43ec18b709b69d174e05abaefa70f9b3054a59935180152eb84ffee1bde"
|
|
40
40
|
}
|
|
41
41
|
]
|
|
42
42
|
}
|
package/publish/gxmcp-sbom.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "gxmcp-provenance/1",
|
|
3
|
-
"version": "3.7.
|
|
4
|
-
"sourceCommit": "
|
|
3
|
+
"version": "3.7.2",
|
|
4
|
+
"sourceCommit": "8bfec41e1fb31839fac72bd5696bf848285a194a",
|
|
5
5
|
"sourceCommitPolicy": "exact-tag",
|
|
6
6
|
"components": [
|
|
7
7
|
{
|
|
8
8
|
"name": "genexus-mcp",
|
|
9
9
|
"lockfile": "package-lock.json",
|
|
10
10
|
"size": 39914,
|
|
11
|
-
"sha256": "
|
|
11
|
+
"sha256": "858f4118fde52b680bc6bd39d52f607cc12c1e54f9d29a7d26bdb60690588d66"
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
14
|
"name": "nexus-ide",
|
|
15
15
|
"lockfile": "src/nexus-ide/package-lock.json",
|
|
16
16
|
"size": 274983,
|
|
17
|
-
"sha256": "
|
|
17
|
+
"sha256": "6e6ad2ac8abc7f5180455cf72ad36906b9532fcab43185a936344e9b952f3882"
|
|
18
18
|
}
|
|
19
19
|
]
|
|
20
20
|
}
|
|
File without changes
|
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
{"name":"genexus_query","description":"Search objects in active KB. Prefixes: name:, type:, usedby:, parent:, parentPath:, description:. name:\"X\" (or bare quoted \"X\") demands exact-name match — use it when you know the object's name. Compact by default. See genexus://kb/tool-help/genexus_query. Requires the KB index to be Ready — check genexus_lifecycle action=status if results look empty.","inputSchema":{"type":"object","properties":{"query":{"type":"string"},"typeFilter":{"type":"string"},"domainFilter":{"type":"string"},"limit":{"type":"integer"},"inline_read_top":{"type":"integer","description":"0-3. Inline reads of top N."},"sort":{"type":"string","enum":["relevance","lastUpdate"],"description":"relevance (default) or lastUpdate (newest first; bypasses score ranking)."},"since":{"type":"string","description":"ISO-8601 UTC. Only items with lastUpdate >= since."},"modifiedBefore":{"type":"string","description":"ISO-8601 UTC. Only items with lastUpdate < modifiedBefore."},"cursor":{"type":"string","description":"Opaque token from prior nextCursor. Use with sort=lastUpdate for stable paging."},"kb":{"type":"string","description":"KB alias."},"axiCompact":{"type":"boolean","description":"Compact projection (default true).","default":true},"exactMatch":{"type":"boolean","description":"Require an exact object-name match."}},"required":["query"],"examples":[{"query":"type:Transaction parent:Customers"},{"query":"\"Customer\"","limit":5}]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},
|
|
6
6
|
{"name":"genexus_list_objects","description":"List objects with pagination. Feed nextOffset until hasMore=false. Every item exposes its persisted GUID and path; verbose=true also exposes the typed EntityKey when available.","inputSchema":{"type":"object","properties":{"filter":{"type":"string","description":"Legacy: name OR description. Prefer nameFilter/descriptionFilter."},"nameFilter":{"type":"string","description":"Substring on name."},"descriptionFilter":{"type":"string","description":"Substring on description."},"pathPrefix":{"type":"string","description":"Folder prefix, e.g. 'Root Module/X/'."},"limit":{"type":"integer"},"offset":{"type":"integer"},"parent":{"type":"string"},"parentPath":{"type":"string"},"typeFilter":{"type":"string"},"verbose":{"type":"boolean","description":"Full item shape."},"sort":{"type":"string","enum":["name","lastUpdate"],"description":"name (default, type-bucketed) or lastUpdate (newest first)."},"since":{"type":"string","description":"ISO-8601 UTC. Only items with lastUpdate >= since."},"modifiedBefore":{"type":"string","description":"ISO-8601 UTC. Only items with lastUpdate < modifiedBefore."},"cursor":{"type":"string","description":"Opaque token from prior nextCursor. Use with sort=lastUpdate for stable paging."},"inline_read_top":{"type":"integer","description":"0-3. Inline reads of top N."},"kb":{"type":"string","description":"KB alias."},"axiCompact":{"type":"boolean","description":"Compact projection (default true).","default":true},"projection":{"type":"string","enum":["minimal","standard","verbose"],"description":"minimal=name+type+lastUpdate; standard=default compact; verbose=all fields. Overrides axiCompact when set."}},"examples":[{"limit":25},{"typeFilter":"Transaction","limit":10}]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},
|
|
7
7
|
{"name":"genexus_read","description":"Read object code and metadata. Omitting 'part' (RECOMMENDED) returns the COMPLETE object in 1 call (rules with parm, source/events, variables, structure, called signatures) tailored to the object type. Resolve modular objects by name/type, persisted GUID, EntityKey, or path. Pass 'part' only for targeted single-part reads. Response carries versionToken for safe writes. See genexus://kb/tool-help/genexus_read.","inputSchema":{"type":"object","properties":{"name":{"type":"string"},"targets":{"type":"array","items":{"type":"string"}},"guid":{"type":"string","description":"Persisted object GUID from genexus_list_objects."},"entityKey":{"type":"string","description":"Typed GeneXus EntityKey from genexus_list_objects verbose output."},"path":{"type":"string","description":"Module/folder-qualified object path from genexus_list_objects."},"part":{"type":"string","description":"DataSelector: parameters|conditions|orders|projection|definedBy|baseTransaction|baseTable|joins|structure."},"parts":{"type":"array","items":{"type":"string"},"description":"Selected parts; unavailable DataSelector parts appear in unsupportedParts. Mutually exclusive with part/offset/limit."},"offset":{"type":"integer"},"limit":{"type":"integer"},"type":{"type":"string"},"kb":{"type":"string","description":"KB alias."}},"examples":[{"name":"Customer"},{"name":"Customer","type":"Procedure","guid":"<guid-from-list>"},{"name":"Customer","path":"Operations/Customer","type":"Procedure"},{"name":"Customer","part":"Source"}]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},
|
|
8
|
-
{"name":"genexus_edit","description":"Edit object part. name or targets (exclusive). mode: full|patch|ops. dryRun first. async=true returns an operationId for lifecycle polling. Text payloads for Source/Rules/Events/Code must contain real line breaks; literal backslash sequences \\r\\n, \\n, or \\r are rejected before persistence with LiteralLineBreaksDetected. For WWP edit host's PatternInstance NOT the parent WebForm (gets overwritten on reapply). Uncertain about a property/method/event? → resources/read uri=genexus://kb/skills/navigation (or gam-integrated-security / sd-panel-mobile / webpanel-events) first.","inputSchema":{"type":"object","properties":{"name":{"type":"string"},"part":{"type":"string"},"parts":{"type":"array","description":"Multi-part edit on a single object. Each item: {part, content, mode?}. Saves the object once atomically. Text content must use real line breaks; literal backslash sequences \\r\\n, \\n, or \\r are rejected before persistence.","items":{"type":"object","properties":{"part":{"type":"string"},"content":{"type":"string"},"mode":{"type":"string"}},"required":["part","content"]}},"mode":{"type":"string","enum":["full","patch","ops"]},"content":{"type":"string"},"ops":{"type":"array","description":"GeneXus semantic ops (NOT RFC 6902 JSON-Patch). Each item: {op, args}. Supported ops: set_attribute, add_attribute, remove_attribute (Transaction); add_rule, remove_rule (Transaction/Procedure/WebPanel); set_property (any kind). Use mode=patch for textual find/replace.","items":{"type":"object","properties":{"op":{"type":"string","enum":["set_attribute","add_attribute","remove_attribute","add_rule","remove_rule","set_property"]},"args":{"type":"object","description":"Op-specific args. set_attribute: {name, type?, description?}. add_attribute: {name, type, ...}. add_rule: {rule}. set_property: {name, value}."}},"required":["op"]}},"patch":{"type":"object","additionalProperties":true,"description":"Shorthand for {find,replace} on mode=patch: find is the exact existing text, replace is inserted literally (no auto-indentation). Optional opt-in protections: scope bounds the search region, indentation validates the replacement's base indent. Both apply ONLY to this shape — never with operation, mode=ops, targets[], parts[], Insert_After or Append.","properties":{"find":{"type":"string","description":"Exact existing text to find. Real line breaks; tabs/spaces must match the part."},"replace":{"type":"string","description":"Replacement text, inserted literally."},"scope":{"type":"object","required":["start"],"description":"Region delimited by complete-line anchors: editable starts after scope.start's last line and ends before scope.end's first line (EOF when end is omitted). Anchors stay outside the region, are compared with only CRLF/LF normalized, and must each be unique. Errors: ScopeStartRequired, ScopeAnchorNotFound, ScopeAnchorAmbiguous, ScopeAnchorNotComparable. The response reports editableStartLine, editableEndLineExclusive and scopeEndsAtEof.","properties":{"start":{"type":"string","description":"Required. Unique complete-line anchor ending immediately before the editable region."},"end":{"type":"string","description":"Optional. Unique complete-line anchor starting immediately after the editable region. Omitted = region runs to EOF."}}},"indentation":{"type":"object","required":["mode"],"description":"Validates the base indentation of the located match against the first line of replace before persisting; tabs and spaces are distinct and nothing is reformatted. With replaceAll=true every match is validated. Errors: IndentationMismatch, IndentationNotComparable.","properties":{"mode":{"type":"string","enum":["validate"],"description":"validate: block the write when the replacement's base indentation differs from the matched line's."}}}}},"scope":{"type":"object","description":"patch.scope may also be passed at the top level. Honored ONLY by the abbreviated patch={find,replace} form; combined with operation, mode=ops, targets[], parts[], Insert_After or Append the call is rejected with ScopeUnsupportedPatchForm and nothing is written."},"indentation":{"type":"object","description":"patch.indentation may also be passed at the top level. Honored ONLY by the abbreviated patch={find,replace} form; combined with operation, mode=ops, targets[], parts[], Insert_After or Append the call is rejected with IndentationUnsupportedPatchForm and nothing is written."},"context":{"type":"string","description":"Exact existing text to find (Replace) or anchor after (Insert_After). Required for both. For text parts, send real line breaks; literal backslash sequences \\r\\n, \\n, or \\r are rejected before persistence."},"operation":{"type":"string","enum":["Replace","Insert_After","Append"]},"expectedCount":{"type":"integer"},"replaceAll":{"type":"boolean","description":"patch mode only. Apply to ALL occurrences instead of requiring expectedCount to match exactly."},"dryRun":{"type":"boolean"},"async":{"type":"boolean","description":"Run as a background job. Result returns operationId/job_id for genexus_lifecycle polling."},"estimated_seconds":{"type":"integer","description":"When async=true, expected runtime used for progress/job metadata (default 30)."},"verifyRollback":{"type":"boolean"},"targets":{"type":"array","description":"Multi-target Source/Rules writes. Each target may include expectedVersion/baseVersion; all versions are checked before the first write.","items":{"type":"object","properties":{"name":{"type":"string"},"part":{"type":"string"},"content":{"type":"string"},"expectedVersion":{"type":"string"},"baseVersion":{"type":"string"}},"required":["name","content"]}},"type":{"type":"string"},"return_post_state":{"type":"boolean","description":"Omit post_state.diff (default true)."},"verbose":{"type":"boolean","description":"Add ±15-line slices to post_state."},"validate":{"type":"string","enum":["strict","best-effort","only"],"description":"strict (default) aborts on first error and post-write-verifies visual/PatternInstance writes (re-reads + diffs the persisted XML). best-effort applies what compiles and SKIPS the post-write XML re-read/diff (faster on large WebForm/PatternInstance writes; build to confirm). only runs in-memory, no persist."},"validationMode":{"type":"string","enum":["specify"],"description":"Issue #60: run the inline Specify pass (Spec+Gen, no Compile) against the edited object right after the write, returning structured spc*/gen* diagnostics in the same call. Combines with rollbackOnFailure."},"rollbackOnFailure":{"type":"boolean","description":"Explicit rollback only
|
|
8
|
+
{"name":"genexus_edit","description":"Edit object part. name or targets (exclusive). mode: full|patch|ops. dryRun first. async=true returns an operationId for lifecycle polling. Text payloads for Source/Rules/Events/Code must contain real line breaks; literal backslash sequences \\r\\n, \\n, or \\r are rejected before persistence with LiteralLineBreaksDetected. For WWP edit host's PatternInstance NOT the parent WebForm (gets overwritten on reapply). Uncertain about a property/method/event? → resources/read uri=genexus://kb/skills/navigation (or gam-integrated-security / sd-panel-mobile / webpanel-events) first.","inputSchema":{"type":"object","properties":{"name":{"type":"string"},"part":{"type":"string"},"parts":{"type":"array","description":"Multi-part edit on a single object. Each item: {part, content, mode?}. Saves the object once atomically. Text content must use real line breaks; literal backslash sequences \\r\\n, \\n, or \\r are rejected before persistence.","items":{"type":"object","properties":{"part":{"type":"string"},"content":{"type":"string"},"mode":{"type":"string"}},"required":["part","content"]}},"mode":{"type":"string","enum":["full","patch","ops"]},"content":{"type":"string"},"ops":{"type":"array","description":"GeneXus semantic ops (NOT RFC 6902 JSON-Patch). Each item: {op, args}. Supported ops: set_attribute, add_attribute, remove_attribute (Transaction); add_rule, remove_rule (Transaction/Procedure/WebPanel); set_property (any kind). Use mode=patch for textual find/replace.","items":{"type":"object","properties":{"op":{"type":"string","enum":["set_attribute","add_attribute","remove_attribute","add_rule","remove_rule","set_property"]},"args":{"type":"object","description":"Op-specific args. set_attribute: {name, type?, description?}. add_attribute: {name, type, ...}. add_rule: {rule}. set_property: {name, value}."}},"required":["op"]}},"patch":{"type":"object","additionalProperties":true,"description":"Shorthand for {find,replace} on mode=patch: find is the exact existing text, replace is inserted literally (no auto-indentation). Optional opt-in protections: scope bounds the search region, indentation validates the replacement's base indent. Both apply ONLY to this shape — never with operation, mode=ops, targets[], parts[], Insert_After or Append.","properties":{"find":{"type":"string","description":"Exact existing text to find. Real line breaks; tabs/spaces must match the part."},"replace":{"type":"string","description":"Replacement text, inserted literally."},"scope":{"type":"object","required":["start"],"description":"Region delimited by complete-line anchors: editable starts after scope.start's last line and ends before scope.end's first line (EOF when end is omitted). Anchors stay outside the region, are compared with only CRLF/LF normalized, and must each be unique. Errors: ScopeStartRequired, ScopeAnchorNotFound, ScopeAnchorAmbiguous, ScopeAnchorNotComparable. The response reports editableStartLine, editableEndLineExclusive and scopeEndsAtEof.","properties":{"start":{"type":"string","description":"Required. Unique complete-line anchor ending immediately before the editable region."},"end":{"type":"string","description":"Optional. Unique complete-line anchor starting immediately after the editable region. Omitted = region runs to EOF."}}},"indentation":{"type":"object","required":["mode"],"description":"Validates the base indentation of the located match against the first line of replace before persisting; tabs and spaces are distinct and nothing is reformatted. With replaceAll=true every match is validated. Errors: IndentationMismatch, IndentationNotComparable.","properties":{"mode":{"type":"string","enum":["validate"],"description":"validate: block the write when the replacement's base indentation differs from the matched line's."}}}}},"scope":{"type":"object","description":"patch.scope may also be passed at the top level. Honored ONLY by the abbreviated patch={find,replace} form; combined with operation, mode=ops, targets[], parts[], Insert_After or Append the call is rejected with ScopeUnsupportedPatchForm and nothing is written."},"indentation":{"type":"object","description":"patch.indentation may also be passed at the top level. Honored ONLY by the abbreviated patch={find,replace} form; combined with operation, mode=ops, targets[], parts[], Insert_After or Append the call is rejected with IndentationUnsupportedPatchForm and nothing is written."},"context":{"type":"string","description":"Exact existing text to find (Replace) or anchor after (Insert_After). Required for both. For text parts, send real line breaks; literal backslash sequences \\r\\n, \\n, or \\r are rejected before persistence."},"operation":{"type":"string","enum":["Replace","Insert_After","Append"]},"expectedCount":{"type":"integer"},"replaceAll":{"type":"boolean","description":"patch mode only. Apply to ALL occurrences instead of requiring expectedCount to match exactly."},"dryRun":{"type":"boolean"},"async":{"type":"boolean","description":"Run as a background job. Result returns operationId/job_id for genexus_lifecycle polling."},"estimated_seconds":{"type":"integer","description":"When async=true, expected runtime used for progress/job metadata (default 30)."},"verifyRollback":{"type":"boolean"},"targets":{"type":"array","description":"Multi-target Source/Rules writes. Each target may include expectedVersion/baseVersion; all versions are checked before the first write.","items":{"type":"object","properties":{"name":{"type":"string"},"part":{"type":"string"},"content":{"type":"string"},"expectedVersion":{"type":"string"},"baseVersion":{"type":"string"}},"required":["name","content"]}},"type":{"type":"string"},"return_post_state":{"type":"boolean","description":"Omit post_state.diff (default true)."},"verbose":{"type":"boolean","description":"Add ±15-line slices to post_state."},"validate":{"type":"string","enum":["strict","best-effort","only"],"description":"strict (default) aborts on first error and post-write-verifies visual/PatternInstance writes (re-reads + diffs the persisted XML). best-effort applies what compiles and SKIPS the post-write XML re-read/diff (faster on large WebForm/PatternInstance writes; build to confirm). only runs in-memory, no persist."},"validationMode":{"type":"string","enum":["specify"],"description":"Issue #60: run the inline Specify pass (Spec+Gen, no Compile) against the edited object right after the write, returning structured spc*/gen* diagnostics in the same call. Combines with rollbackOnFailure."},"rollbackOnFailure":{"type":"boolean","description":"Explicit rollback only. Full Source verification failure reports AtomicRollbackUnavailable without a restore write until atomic conditional restore is supported. Other paths require a valid snapshot. No rollback when false or omitted."},"requireObjectSave":{"type":"boolean","default":false,"description":"Full Source requires transactional object save. Events patch: dryRun available; real writes blocked by ObjectSaveIsolationUnverified until SDK/pattern save-event isolation is established. No override; baseVersion required."},"forceWrite":{"type":"boolean","default":false,"description":"WebForm only: persist despite SDK WebForm validation errors; response includes validationOverridden=true."},"verifyMode":{"type":"string","enum":["semantic","normalized","exact"],"default":"normalized","description":"Post-save text comparison. Full exact compares public-read text verbatim; patch exact retains logical CRLF/LF equivalence. normalized ignores EOL, BOM, trailing whitespace and blank lines; semantic also tolerates casing/spacing. Fresh reread always required. sdkSaveCompleted/saved report physical save; persistedStateKnown and postSaveVerification report read evidence. Mismatch never retries automatically."},"visualVerify":{"type":"boolean","default":false,"description":"Post-edit headless screenshot + pixel-diff vs baseline. See tool-help."},"baseVersion":{"type":"string","description":"Optimistic concurrency: pass the versionToken from the genexus_read this edit is based on. If the object changed since (e.g. edited in the IDE), the write is refused with VersionConflict instead of overwriting the newer version. Omit to skip the check."},"expectedVersion":{"type":"string","description":"Alias of baseVersion. The write is refused when the current version no longer matches."},"concurrencyPolicy":{"type":"string","enum":["warn","fail_if_open"],"default":"warn","description":"warn (default) or fail_if_open if open in GeneXus IDE."},"autoDeclareVariables":{"type":"boolean","default":false,"description":"When true, scans updated source for newly referenced &Variable tokens and auto-declares them in VariablesPart."},"kb":{"type":"string","description":"KB alias."},"changeSet":{"type":"object","required":["action","changes"],"properties":{"action":{"type":"string","enum":["preview","validate","apply"]},"changes":{"type":"array","items":{"type":"object","required":["name","content"],"properties":{"name":{"type":"string"},"part":{"type":"string","enum":["Source","Rules","Variables"]},"content":{"type":"string"},"expectedVersion":{"type":"string"}}}},"changeSetId":{"type":"string"},"baseRevision":{"type":"string"}}},"module":{"type":"string","description":"mode=ops: Transaction module for modular objects."}},"examples":[{"name":"Customer","mode":"patch","part":"Source","patch":{"find":"old","replace":"new"}},{"name":"Customer","mode":"patch","part":"Rules","patch":{"find":"error(","replace":"msg("},"dryRun":true},{"name":"Customer","mode":"patch","part":"Source","patch":{"find":"old","replace":"new","scope":{"start":"// Banco B","end":"// Proximo banco"}}}]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":false}},
|
|
9
9
|
{"name":"genexus_inspect","description":"Use this for a compact object snapshot: metadata, variables, structure, signature and navigation context. Modular objects accept persisted GUID, EntityKey, or path in addition to name/type. Don't use it when you need full Source or exact part bytes; use genexus_read for that. runtimeIds needs a prior build.","inputSchema":{"type":"object","properties":{"name":{"type":"string"},"guid":{"type":"string","description":"Persisted object GUID from genexus_list_objects."},"entityKey":{"type":"string","description":"Typed GeneXus EntityKey from genexus_list_objects verbose output."},"path":{"type":"string","description":"Module/folder-qualified object path from genexus_list_objects."},"include":{"type":"array","items":{"type":"string","enum":["metadata","variables","signature","structure","parts","controls","events_repertoire","callers","runtimeIds"]}},"projection":{"type":"string","enum":["minimal","standard","verbose"],"description":"Token budget. minimal=name/type/lastUpdate; standard=default (vars≤40 name+type, source heads 1200c); verbose=full vars + 8000c heads."},"type":{"type":"string"},"kb":{"type":"string","description":"KB alias."},"verbose":{"type":"boolean","description":"Include verbose diagnostic fields."}},"examples":[{"name":"Customer"},{"name":"Customer","type":"Procedure","path":"Operations/Customer"},{"name":"Customer","include":["variables","signature"]}]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},
|
|
10
10
|
{"name":"genexus_analyze","description":"Use this for cross-object semantic analysis. mode=context (alias deep_context) returns 360° task context in 1 call (object + called procedures' parm signatures + referenced tables' schemas/PKs + SDTs + callers). Other modes: impact, callers, hierarchy, navigation, linter, summary, explain. mode=explain is compatibility-only: it preserves the legacy response envelope and returns NotImplemented; use mode=summary for a concise overview, mode=context for 360° task context, or genexus_read for source. Requires Ready index for impact/callers.","inputSchema":{"type":"object","properties":{"name":{"type":"string"},"mode":{"type":"string","enum":["context","deep_context","linter","navigation","hierarchy","impact","cross_platform_impact","callers","event_flow","data_context","ui_context","pattern_metadata","summary","dependency_heatmap","code_metrics","kb_stats","table_relations","explain"]},"code":{"type":"string","description":"mode=explain: legacy code snippet carried through the compatibility-only envelope; the result is NotImplemented. Use mode=summary, mode=context, or genexus_read for supported analysis."},"cursor":{"type":"string","description":"mode=context: continuation cursor returned by a budgeted context page."},"format":{"type":"string","enum":["json","ascii"],"description":"mode=dependency_heatmap: ascii adds rendered bar chart."},"kb":{"type":"string","description":"KB alias."},"maxBytes":{"type":"integer","description":"mode=context: maximum UTF-8 bytes for the returned context bundle (bounded by the server)."},"waitForIndex":{"type":"boolean","description":"mode=impact: block up to 30s for Ready index (default true).","default":true},"dryRun":{"type":"boolean","description":"mode=linter: with fix=true, reject the unsupported combination before any SDK read; with fix=false, lint remains read-only."},"fix":{"type":"boolean","description":"mode=linter: apply automatic fixes to the KB."},"top":{"type":"integer","description":"mode=code_metrics: maximum results (default 25)."},"waitTimeoutMs":{"type":"integer","description":"mode=impact: maximum index wait in milliseconds."}},"required":["mode"],"examples":[{"name":"Customer","mode":"impact"},{"name":"Customer","mode":"summary"}]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false}},
|
|
11
11
|
{"name":"genexus_lifecycle","description":"Build, validate, index, or poll the KB. action=build_all runs the native incremental Build All for the entire selected KB (ForceRebuild=false); it rejects target, refuses silent reorganization, and returns completion evidence. action=rebuild remains the forced Rebuild All path. action=specify runs Spec+Gen only. action=build with mode=compile_check checks targets plus transitive callers without KB-wide DeveloperMenu regeneration. Long operations are async with operationId. dryRun=true previews without executing. Build results carry generateEvidence and effective_status. See genexus://kb/tool-help/genexus_lifecycle for actions and target formats.","inputSchema":{"type":"object","properties":{"action":{"type":"string","enum":["build","build_all","cancel","specify","rebuild","reorg","reorg_preview","validate","validate-kb","sync","index","status","result","snapshots-list","snapshots-restore","inspect","reconcile"],"description":"Lifecycle action to perform."},"mode":{"type":"string","enum":["compile_check"],"description":"With action=build: compile_check spec+gen+compiles target(s) plus their transitive callers and SKIPS the KB-wide DeveloperMenu regen (the dominant build-all cost). Fast 'did my edit break the build?' check; requires target."},"target":{"type":"string","description":"Object/task ID/op:<id>. compile_check accepts unique name, Type:Name, GUID; no paths. build_all rejects target."},"code":{"type":"string","description":"validate: in-memory code to check without persisting."},"limit":{"type":"integer","description":"validate-kb: maximum number of objects/conditions to validate."},"snapshotPath":{"type":"string","description":"snapshots-restore: path to pattern snapshot to restore."},"estimated_seconds":{"type":"integer","description":"Build: <20 sync, >=20 async (default 60)."},"wait_seconds":{"type":"integer","description":"Status/build long-poll cap, 0-600s."},"wait_until_done":{"type":"boolean","description":"Build/build_all/rebuild: block in one turn until terminal (up to wait_seconds, default 600)."},"wait":{"type":"integer","description":"Status block, 0-600s. With a build taskId (or since): event-driven, returns on change. On index status with no since: blocks until index is Ready."},"since":{"type":"string","description":"Status: prior _meta.snapshot for chained waits."},"freshness":{"type":"string","enum":["current","stale","refreshing"],"description":"Status: freshness target for the wait. With wait and no since, the call blocks until the index status is Ready AND freshness matches, then reports waitSatisfied. Use freshness=current to wait for a warm-start delta refresh to finish (a snapshot restored from the warm cache is Ready but stale, so a status-only wait returns immediately)."},"compact":{"type":"boolean","description":"Status: counts + top-10 errors (default true)."},"force":{"type":"boolean","description":"Index: full SDK rescan (clears snapshot)."},"dryRun":{"type":"boolean","default":false,"description":"build/build_all/rebuild/index: returns the plan without executing."},"environment":{"type":"string","description":"Build: target environment name/folder. Switches active environment before building."},"includeCallees":{"type":"string","enum":["none","direct","transitive"],"description":"Build: expand call graph so callees compile first (default transitive)."},"callers":{"type":"boolean","description":"compile_check: expand transitive callers of the target (default true). Set false for a target-only check when the target is a base transaction/BC with a huge caller closure."},"callerCap":{"type":"integer","description":"compile_check: max callers to pull into the check (default 40). Closure beyond this is truncated and flagged."},"deploy":{"type":"boolean","description":"Build: force the full deploy (Theme/Image/Style/Module copy to web/bin + WebAppConfig) so the built object is runnable, not just compiled. Default false (fast compile-only path). Slower; use when you need to run/preview the object."},"buildPlanCap":{"type":"integer","description":"Build: max nodes before BuildPlanTooLarge (default 200)."},"kb":{"type":"string","description":"KB alias."},"part":{"type":"string","description":"validate: specific object part to check (e.g. Source, Rules)."},"page":{"type":"integer","description":"status/result: 1-based page number for paginated results."},"pageSize":{"type":"integer","description":"status/result: page size for paginated results (default 50)."},"page_size":{"type":"integer","description":"status/result: snake_case alias for pageSize."},"notifyOnFailure":{"type":"string","description":"build: Slack/Discord webhook URL to notify on terminal build failure."},"skipFullDeploy":{"type":"boolean","description":"build: skip full deployment stage to speed up compile pass."},"fastIncremental":{"type":"boolean","description":"build: experimental fast incremental build opt-in."},"operationKey":{"type":"string","description":"inspect/reconcile: original idempotency key; journal lookup is hash-scoped to the resolved KB."},"operationTool":{"type":"string","description":"inspect/reconcile: canonical mutating tool that owns the idempotency key, e.g. genexus_edit."},"confirmed":{"type":"boolean","description":"reconcile: must be true after independently reading the affected target; this never authorizes a retry with the same key."},"verification":{"type":"string","description":"reconcile: short operator/model verification statement. Only a hash is persisted; source and KB content are never journaled."},"observedTargetIds":{"type":"array","items":{"type":"string"},"description":"reconcile: target names observed by an independent read; send one name as a single-item array. Must match the durable target fence."},"observedRevision":{"type":"string","description":"reconcile: revision/version observed by an independent read; must match the durable revision fence."}},"required":["action"],"examples":[{"action":"build"},{"action":"build_all"},{"action":"status","target":"op:abc123"},{"action":"build","mode":"compile_check","target":"MyObject"},{"action":"inspect","operationTool":"genexus_edit","operationKey":"edit_20260905_01"}]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"outputSchema":{"type":"object","description":"Structured lifecycle result. Action-specific fields remain additive; text content is preserved for legacy clients.","properties":{"status":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"},"error":{"type":"string"},"operationId":{"type":"string"},"job_id":{"type":"string"},"pollTarget":{"type":"string"},"isError":{"type":"boolean"}},"additionalProperties":true}},
|
|
12
12
|
{"name":"genexus_test","description":"Execute native GeneXus tests (GXtest).","inputSchema":{"type":"object","properties":{"name":{"type":"string"},"kb":{"type":"string","description":"KB alias."}},"required":["name"],"examples":[{"name":"MyTestProc"}]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":true}},
|
|
13
13
|
{"name":"genexus_sdk_probe","description":"Read the GeneXus SDK surface. mode=surface dumps types/methods/props to docs/sdk-probe/; mode=capabilities returns an in-memory capability matrix with honest signature-probe status.","inputSchema":{"type":"object","properties":{"mode":{"type":"string","enum":["surface","capabilities"],"description":"surface (default) writes the diagnostic probe; capabilities is read-only and returns status/evidence."},"outputDir":{"type":"string","description":"Absolute path for mode=surface. Default <repo>/docs/sdk-probe/."},"kb":{"type":"string","description":"KB alias."}},"examples":[{},{"mode":"capabilities"}]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false}},
|
|
14
14
|
{"name":"genexus_worker_reload","description":"Reload worker. mode=soft drains and respawns; mode=hard copies sourceDir during the drain window and respawns. force=true kills and respawns a wedged Worker, but cannot be combined with mode=hard; no Worker is stopped when that combination is rejected. See tool-help.","inputSchema":{"type":"object","properties":{"mode":{"type":"string","enum":["soft","hard"]},"force":{"type":"boolean","description":"Bypass drain; gateway kills + respawns. Use with mode=soft when the Worker is wedged; force=true + mode=hard is rejected before stopping anything."},"sourceDir":{"type":"string","description":"Required for mode=hard."},"drainTimeoutMs":{"type":"integer","description":"Soft only; default 30000."},"alias":{"type":"string","description":"KB alias to reload when more than one worker is open."},"kb":{"type":"string","description":"Alias of alias."}},"examples":[{"mode":"soft"},{"mode":"hard","sourceDir":"C:\\Projetos\\Genexus18MCP\\src\\GxMcp.Worker\\bin\\Debug"}]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},
|
|
15
|
-
|
|
15
|
+
{"name":"genexus_connection_recover","description":"Probes every open worker and recovers unhealthy ones (force=true targets all). journal_status inspects recovery fences; journal_repair atomically merges valid candidates and verifies persistence. Repair defaults to dryRun=true, preserves pending reads and never touches Workers/KB. Do not combine journal actions with force.","inputSchema":{"type":"object","properties":{"force":{"type":"boolean","default":false,"description":"Recover ALL workers, even responsive ones."},"action":{"type":"string","enum":["recover","journal_status","journal_repair"],"default":"recover","description":"Worker recovery, journal inspection or explicit repair."},"dryRun":{"type":"boolean","description":"Preview journal_repair; explicitly false to persist reconciliation.","default":true}},"examples":[{},{"force":true}]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},
|
|
16
16
|
{"name":"genexus_delete_object","description":"Delete an object from the KB through its native SDK identity. Irreversible — confirm=true required. Inspects native incoming references first; dryRun=true previews without deleting it.","inputSchema":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string"},"confirm":{"type":"boolean"},"dryRun":{"type":"boolean","default":false,"description":"When true, returns the resolved object and native references without deleting it."},"expectedVersion":{"type":"string","description":"Optional optimistic-concurrency token returned by a prior dry run."},"kb":{"type":"string","description":"KB alias."}},"required":["name"],"examples":[{"name":"ObsoletePanel","type":"WebPanel","confirm":true},{"name":"TemporaryDomain","type":"Domain","confirm":true,"dryRun":true}]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false}},
|
|
17
17
|
{"name":"genexus_refactor","description":"Run GeneXus refactor: rename, extract procedure, extract local subroutine, or WWP condition set. For KB-wide rename with call-site patching (RenameObject/RenameAttribute), the response includes a patched-site count from RefactorService. dryRun=true previews what would change without persisting.","inputSchema":{"type":"object","properties":{"action":{"type":"string","enum":["RenameAttribute","RenameVariable","RenameObject","ExtractProcedure","ExtractSubroutine","WWPSetCondition"],"description":"Refactoring operation to execute; rename and extraction actions change KB source or metadata."},"target":{"type":"string","description":"Primary object or symbol to refactor."},"newName":{"type":"string","description":"New name for the renamed object, attribute, or variable."},"objectName":{"type":"string","description":"RenameVariable: target object name containing the variable."},"code":{"type":"string","description":"ExtractProcedure/ExtractSubroutine: code block to extract."},"procedureName":{"type":"string","description":"ExtractProcedure: name for the newly created Procedure."},"subroutineName":{"type":"string","description":"ExtractSubroutine: name for the newly created Subroutine."},"controlAttribute":{"type":"string","description":"WWPSetCondition: control or attribute name to attach condition."},"value":{"type":"string","description":"WWPSetCondition: condition expression to set."},"type":{"type":"string","description":"RenameObject: object type (e.g. WebPanel, Transaction, Procedure) to disambiguate when several objects share the name — e.g. a WebPanel vs the same-named Table behind a Transaction. Ignored by RenameAttribute/RenameVariable."},"dryRun":{"type":"boolean","default":false,"description":"When true, returns what would be changed without persisting."},"kb":{"type":"string","description":"KB alias."}},"required":["action"],"examples":[{"action":"RenameObject","target":"Customer","newName":"Client"},{"action":"RenameAttribute","target":"CustomerId","newName":"ClientId"},{"action":"ExtractSubroutine","target":"Customer","code":"&Total = 0","subroutineName":"ResetTotal"}]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false}},
|
|
18
18
|
{"name":"genexus_run_object","description":"Resolve runtime URL for an object (webRoot + aspx + encoded args). gamSession='auto'|{user,pass,...} captures GAM cookies. Does NOT open a browser. dryRun=true returns the resolved URL without performing GAM login.","inputSchema":{"type":"object","properties":{"name":{"type":"string"},"args":{"type":"array","items":{"type":"string"},"description":"Positional parameter values."},"gamSession":{"description":"'auto' (use GXMCP_GAM_USER/PASS env) or {user, pass, repository?, loginUrl?}."},"dryRun":{"type":"boolean","default":false,"description":"When true, returns the resolved URL without performing the GAM login step."},"kb":{"type":"string","description":"KB alias."}},"required":["name"],"examples":[{"name":"WPMain"},{"name":"WPCustomer","args":["42"]}]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":true}},
|
|
@@ -32,18 +32,18 @@
|
|
|
32
32
|
{"name":"genexus_security","description":"Audit KB security. action=audit_gam scans GAM/env props; action=scan_secrets greps Source for credential-shaped literals; action=scan_native drives the native GeneXus Security Scanner (ISecurityScannerService). Returns findings with severity.","inputSchema":{"type":"object","required":["action"],"properties":{"action":{"type":"string","enum":["audit_gam","scan_secrets","scan_native"],"description":"audit_gam: scans GAM and environment properties; scan_secrets: greps Source for credentials; scan_native: drives native GeneXus Security Scanner."},"kb":{"type":"string","description":"KB alias."}},"examples":[{"action":"audit_gam"},{"action":"scan_secrets"}]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},
|
|
33
33
|
{"name":"genexus_doctor","description":"Health check: GX install, KB state, worker, cache age, recent telemetry. Paste output for triage when something feels off. When more than one KB is open, pass kb=<alias> to pick which one to diagnose.","inputSchema":{"type":"object","properties":{"kb":{"type":"string","description":"Alias of the KB to diagnose. Optional; required only when multiple KBs are open (otherwise the single open / default KB is used)."}},"additionalProperties":false,"examples":[{},{"kb":"mykb"}]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},
|
|
34
34
|
{"name":"genexus_edit_form","description":"Semantic WebForm edits. Actions: add_textblock, add_button, set_visibility, remove_control, wrap_in_fieldset.","inputSchema":{"type":"object","properties":{"action":{"type":"string","enum":["add_textblock","add_button","set_visibility","remove_control","wrap_in_fieldset"],"description":"Semantic WebForm control operation to execute."},"name":{"type":"string","description":"Target WebPanel or Transaction name."},"parent":{"type":"string","description":"Parent control ID to insert the new control into."},"position":{"type":"string","description":"first|last|after:<id>"},"caption":{"type":"string","description":"add_textblock/add_button: caption text."},"format":{"type":"string","enum":["Text","HTML"],"description":"add_textblock: format (Text or HTML)."},"event":{"type":"string","description":"add_button: event name to trigger on click."},"controlId":{"type":"string","description":"set_visibility/remove_control: control ID to target."},"controlIds":{"type":"array","items":{"type":"string"},"description":"wrap_in_fieldset: list of control IDs to wrap inside the fieldset."},"legend":{"type":"string","description":"wrap_in_fieldset: legend text for the fieldset container."},"visible":{"type":"boolean","description":"set_visibility: visibility state (true or false)."},"dryRun":{"type":"boolean","description":"Preview form modifications without persisting."},"kb":{"type":"string","description":"KB alias."}},"required":["action","name"],"examples":[{"action":"add_button","name":"WPMain","caption":"Confirmar","event":"OnConfirm"},{"action":"set_visibility","name":"WPMain","controlId":"GrpDetail","visible":false}]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false}},
|
|
35
|
-
{"name":"genexus_compare","description":"
|
|
35
|
+
{"name":"genexus_compare","description":"Read-only SDK comparison. content adds diffs (part=read alias, partType, unified/omittedReason), preserving equal/differences. CRLF/CR to LF. Limits: input 1M UTF-16 units, diff 16K/part, JSON evidence 128KiB total; excess omitted. properties unchanged. See genexus_help.","inputSchema":{"type":"object","required":["objectA","objectB"],"properties":{"objectA":{"type":"string"},"objectB":{"type":"string"},"type":{"type":"string","description":"Object type filter applied to both lookups, e.g. 'Transaction'."},"mode":{"type":"string","enum":["content","properties"],"description":"content (default) or properties."},"kb":{"type":"string","description":"KB alias."}},"examples":[{"objectA":"Customer","objectB":"CustomerV2"},{"objectA":"Customer","objectB":"CustomerV2","mode":"properties"}]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},
|
|
36
36
|
{"name":"genexus_module","description":"GeneXus Module Manager over the SDK's IModuleManagerService. action=list (read-only: installed Module KB objects) | install (opcFile=<path to .opc file>, or name[+version] to install a named module) | install_builtin (name=<built-in module>) | update (name+version) | package/publish/restore (module lifecycle) | add_modules_server/search_modules_in_servers (configured module servers).","inputSchema":{"type":"object","required":["action"],"properties":{"action":{"type":"string","enum":["install","install_builtin","update","list","package","publish","restore","list_modules_servers","add_modules_server","search_modules_in_servers"],"description":"Module Manager operation to inspect, install, or update a module."},"opcFile":{"type":"string","description":"install: absolute path to a .opc module package file."},"name":{"type":"string","description":"install (by name)/install_builtin/update: module name."},"version":{"type":"string","description":"install (by name)/update: target module version."},"outputPath":{"type":"string","description":"package: output directory; publish: output .opc file."},"outputDirectory":{"type":"string","description":"Alias of outputPath for package."},"rebuild":{"type":"boolean","description":"package: include a rebuild before packaging."},"confirm":{"type":"boolean","description":"Required for restore/publish/package when the operation changes KB or publishes externally."},"server":{"type":"string","description":"restore/search_modules_in_servers: configured module server name."},"serverType":{"type":"string","enum":["Directory","Nexus","NexusNuGet","ModuleServer"],"description":"add_modules_server: native ServerType."},"source":{"type":"string","description":"add_modules_server: server URL or directory source."},"filter":{"type":"string","description":"search_modules_in_servers: module name/version filter."},"preserveConfiguration":{"type":"boolean","description":"add_modules_server: preserve the existing server configuration when supported."},"kb":{"type":"string","description":"KB alias."}},"examples":[{"action":"list"},{"action":"install_builtin","name":"GeneXusGAM"}]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":false}},
|
|
37
37
|
{"name":"genexus_merge","description":"Merge two (or three, with an ancestor) KB objects via the SDK's IMergeService. mode=objects only (mode=models is unsupported — needs multiple KBModel instances not available in this worker). Omit objectBase for a 2-way merge (ignoreConflicts applies); pass objectBase for a 3-way merge. dryRun (default true) reports what would merge via IComparerService WITHOUT writing; dryRun=false performs the merge and saves it. WRITE + destructive.","inputSchema":{"type":"object","required":["objectLeft","objectRight"],"properties":{"mode":{"type":"string","enum":["objects"],"description":"Only 'objects' is supported."},"objectLeft":{"type":"string"},"objectRight":{"type":"string"},"objectBase":{"type":"string","description":"Optional common ancestor. Omit for a 2-way merge; pass for a 3-way merge."},"type":{"type":"string","description":"Object type filter applied to all lookups, e.g. 'Transaction'."},"ignoreConflicts":{"type":"boolean","description":"2-way merge only: let the SDK auto-resolve conflicting parts instead of failing. Default false."},"dryRun":{"type":"boolean","default":true,"description":"true (default): report-only, no SDK MergeObjects call, nothing written. false: perform the merge and save it."},"kb":{"type":"string","description":"KB alias."}},"examples":[{"objectLeft":"Customer","objectRight":"CustomerV2"},{"objectBase":"CustomerBase","objectLeft":"Customer","objectRight":"CustomerV2","dryRun":false}]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":false}},
|
|
38
38
|
{"name":"genexus_gxserver","description":"GxServer (Team Development) sync. Read: status|pending|ignored|conflicts|history. pending lists locally-changed objects, each flagged ignoredForCommit (true = in the IDE 'Ignored Objects' tab, skipped by a full commit). ignored lists ONLY the excluded objects: commitIgnored (IDE Commit > Ignored Objects) + updateIgnored (IDE Update > Ignored Objects). Write (destructive; requires a GXserver-linked KB): commit (message; optional targets[] = commit ONLY those pending objects; reports committedObjects + remoteVersion) | update (applies changes into local KB; apply=false = download only; leaves conflicts flagged) | lock (target) | resolve (targets[] + strategy). theirs/automerge/update talk to the server and need creds via GXMCP_TEAMDEV_USER/PASSWORD env (url auto-resolves). Returns {connected:false} when KB is not linked.","inputSchema":{"type":"object","required":["action"],"properties":{"action":{"type":"string","enum":["status","pending","ignored","conflicts","history","commit","update","lock","resolve","pipeline_list","pipeline_runs","pipeline_output","pipeline_run","pipeline_abort"],"description":"GXserver/Team Development or CI pipeline operation to perform."},"project":{"type":"string","description":"pipeline_*: CI pipeline/project name (from pipeline_list)."},"buildId":{"type":"integer","description":"pipeline_output: build id to fetch output for."},"rebuild":{"type":"boolean","description":"pipeline_run: full rebuild instead of incremental."},"runTests":{"type":"boolean","description":"pipeline_run: run tests as part of the pipeline."},"confirm":{"type":"boolean","description":"pipeline_run/pipeline_abort: required (these trigger/cancel a build)."},"limit":{"type":"integer","description":"history only; default 10, max 200."},"message":{"type":"string","description":"commit: commit comment."},"force":{"type":"boolean","description":"commit: force commit despite pending server-side changes."},"apply":{"type":"boolean","description":"update: apply changes into local KB (default true); false = download package only."},"async":{"type":"boolean","description":"update/commit: run as a background job — returns an operationId immediately; poll genexus_lifecycle(action=status|result, target=op:<id>). Use for a large update that would exceed the sync window."},"strategy":{"type":"string","enum":["mine","theirs","automerge"],"description":"resolve: which version wins — mine (keep local, default, creds-free), theirs (take server), automerge (3-way merge). theirs/automerge need server creds."},"target":{"type":"string","description":"lock: object name to lock."},"targets":{"type":"array","items":{"type":"string"},"description":"commit: partial commit — object names to commit (all other pending objects are excluded). resolve: conflicted object names to resolve. Names must appear in action=pending/conflicts."},"kb":{"type":"string","description":"KB alias."}},"examples":[{"action":"status"},{"action":"commit","message":"Fix Customer validation"},{"action":"commit","message":"Ship my proc only","targets":["ApiCtlObjTransicionar"]},{"action":"update"},{"action":"resolve","targets":["Customer"],"strategy":"automerge"}]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":false}},
|
|
39
39
|
{"name":"genexus_kb_version","description":"SDK KB version tree via KBVersionHelper. list and changed_objects are read-only; changed_objects compares active Design with a frozen version and returns paged NEW/CHANGED items without SQL. Other actions mutate. createdAt may be unavailable; lastUpdate is separate.","inputSchema":{"type":"object","required":["action"],"properties":{"action":{"type":"string","enum":["list","changed_objects","freeze","branch","set_active","revert"],"description":"Version delta or tree operation."},"name":{"type":"string","description":"New version/branch name (freeze/branch)."},"description":{"type":"string","description":"New version/branch description (freeze/branch)."},"parentVersion":{"type":"string","description":"Parent version name (freeze/branch). Defaults to the active version."},"targetVersion":{"type":"string","description":"Version to activate (set_active) or revert to (revert)."},"fromVersion":{"type":"string","description":"changed_objects frozen baseline; revert source; omit for latest frozen."},"offset":{"type":"integer","minimum":0,"description":"offset."},"limit":{"type":"integer","minimum":1,"maximum":200,"description":"limit."},"backupModel":{"type":"boolean","description":"freeze."},"includeEnvironments":{"type":"boolean","description":"branch."},"autoUpdate":{"type":"boolean","description":"set_active."},"kb":{"type":"string","description":"KB alias."}},"examples":[{"action":"list"},{"action":"changed_objects","fromVersion":"v1.0"},{"action":"freeze","name":"v1.0","description":"Release 1.0"},{"action":"set_active","targetVersion":"Trunk"}]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":false}},
|
|
40
40
|
{"name":"genexus_browser","description":"Headless-browser verification umbrella. action=smoke (HTTP 200 + clean console), a11y (axe), wcag (caption/tooltip lint), capture (console/network/exceptions), cross (multi-engine), preview (render WebPanel + capture HTML/a11y/screenshot, optionally diff baseline). preview uses mode=render|run (default render; run auto-resolves the KB launcher, IDE F5 parity).","inputSchema":{"type":"object","required":["action"],"properties":{"action":{"type":"string","enum":["smoke","a11y","wcag","capture","cross","preview"],"description":"Browser verification operation to execute."},"name":{"type":"string","description":"WebPanel name."},"mode":{"type":"string","enum":["render","run"],"description":"preview only."},"capture":{"type":"array","items":{"type":"string"},"description":"capture|cross|preview channels: console|network|exceptions|html|a11y|screenshot."},"browsers":{"type":"array","items":{"type":"string","enum":["chrome","firefox","safari","webkit"]},"description":"cross only."},"parms":{"type":"object","description":"preview only."},"launcher":{"type":"string","description":"preview only."},"buildFirst":{"type":"boolean","description":"preview only."},"waitMs":{"type":"integer","description":"preview only."},"diffBaseline":{"type":"boolean","description":"preview only."},"updateBaseline":{"type":"boolean","description":"preview only."},"fill":{"type":"object","description":"preview only."},"click":{"type":"string","description":"preview only."},"auth":{"type":"object","description":"preview only."},"emulate":{"type":"string","enum":["iPhone12","iPhone15Pro","iPadPro","Pixel7","desktop1920","desktop1280"],"description":"preview only."},"network":{"type":"string","enum":["fast","slow3g","fast3g","offline"],"description":"preview only."},"kb":{"type":"string","description":"KB alias."}},"examples":[{"action":"preview","name":"WPMain"},{"action":"cross","name":"WPMain","browsers":["chrome","firefox"]}]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":true}},
|
|
41
|
-
{"name":"genexus_db","description":"Database umbrella.
|
|
41
|
+
{"name":"genexus_db","description":"Database umbrella. Actions: drift_check|drift_report; optimize_analyze|optimize_suggest|optimize_report; sql_ddl|sql_navigation; sample_data; records_query|records_insert|records_update (typed Transaction rows; query read-only; writes dryRun; no business rules); types_list|types_describe|types_validate; reorg_impact; reorg_preview (non-mutating; deep uses ImpactDatabase); translations_import.","inputSchema":{"type":"object","required":["action"],"properties":{"action":{"type":"string","enum":["drift_check","drift_report","optimize_analyze","optimize_suggest","optimize_report","sql_ddl","sql_navigation","sample_data","records_query","records_insert","records_update","types_list","types_describe","types_validate","translations_import","reorg_impact","reorg_preview"],"description":"Database operation. records_query is read-only; records_insert/records_update default to dryRun=true and require the matching single-use v2 preview token for persistence."},"deep":{"type":"boolean","description":"reorg_impact/reorg_preview only: run ISpecifierService.ImpactDatabase (specification, build-heavy) for the authoritative AnalysisResult. Default false (cheap timestamp heuristic)."},"name":{"type":"string","description":"Object/transaction/type name."},"trn":{"type":"string","description":"sample_data: Transaction name."},"transaction":{"type":"string","description":"records_*: root-level Transaction name."},"dataStore":{"type":"string","description":"records_*: existing active-environment datastore; defaults to the SDK default."},"dataStoreAlias":{"type":"string","description":"records_query: profile alias; no credentials."},"where":{"type":"object","description":"records_query/update: equality filters only; update requires a filter."},"values":{"type":"object","description":"records_insert/update: typed attribute values."},"fields":{"type":"array","items":{"type":"string"},"description":"records_query: optional root-attribute projection."},"databaseManagedFields":{"type":"array","items":{"type":"string"},"description":"records_*: reviewed trigger-maintained fields; excludes keys and supplied values. Included in the preview token."},"limit":{"type":"integer","description":"records_query: 1-1000; default 100."},"expectedCount":{"type":"integer","description":"records_update: defaults to exactly one matched record."},"expectedVersion":{"type":"string","description":"records_*: v2 token from the matching write dry-run; query/v1 tokens cannot authorize writes."},"versionToken":{"type":"string","description":"records_*: alias of expectedVersion."},"dryRun":{"type":"boolean","default":true,"description":"records_insert/update: validate and reread the plan without writing."},"rollbackOnFailure":{"type":"boolean","default":true,"description":"records_*: default true; validation failures roll back before commit. Post-commit compensation is refused to preserve concurrent writers."},"timeoutSeconds":{"type":"integer","description":"records_*: command timeout, 1-60 seconds."},"rows":{"type":"integer","description":"sample_data: 1-1000; default 5."},"includeSubordinated":{"type":"boolean","description":"sql_ddl only."},"levelNumber":{"type":"integer","description":"sql_navigation only."},"includeExecutionPlan":{"type":"boolean","description":"sql_navigation."},"includeIndexAdvisor":{"type":"boolean","description":"sql_navigation."},"format":{"type":"string","enum":["json","markdown"],"description":"optimize_report only."},"kind":{"type":"string","enum":["domain","sdt","all"],"description":"types_list filter."},"value":{"type":"string","description":"types_validate."},"type":{"type":"string","description":"types_validate / disambiguator."},"inputPath":{"type":"string","description":"translations_import: CSV path."},"kb":{"type":"string","description":"KB alias."}},"examples":[{"action":"drift_check"},{"action":"sql_ddl","name":"Customer"},{"action":"records_query","dataStoreAlias":"production","transaction":"Order","where":{"OrderId":1},"limit":20,"timeoutSeconds":20}]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false}},
|
|
42
42
|
{"name":"genexus_versioning","description":"Versioning umbrella. action: history_list|history_get|history_save|history_restore (snapshot store; restore+discard=true is IDE 'Discard changes' parity) | undo (revert last N edits) | time_travel (recover bytes from a past git commit) | blame (git blame an object part) | diff (text: mode=textVsText|currentVsText) | diff_generated (against=last-build|git-head).","inputSchema":{"type":"object","required":["action"],"properties":{"action":{"type":"string","enum":["history_list","history_get","history_save","history_restore","undo","time_travel","blame","diff","diff_generated"],"description":"History, diff, time-travel, or rollback operation to perform."},"name":{"type":"string","description":"Object name for history, diff, time_travel, or blame."},"part":{"type":"string","description":"Object part name, e.g. Source, Rules, Events."},"partName":{"type":"string","description":"Legacy alias for part on history actions."},"versionId":{"type":"integer","description":"history_get/history_restore: numerical version ID."},"snapshot":{"type":"string","description":"history_restore: snapshot label or path to restore."},"discard":{"type":"boolean","description":"history_restore: true for IDE 'Discard changes' parity."},"dryRun":{"type":"boolean","description":"history_restore/undo: preview without mutating the KB."},"last":{"type":"integer","description":"undo: default 1, max 20."},"at":{"type":"string","description":"time_travel: ISO-8601 or commit sha."},"line":{"type":"integer","description":"blame: 1-based line number to annotate."},"filePath":{"type":"string","description":"blame: absolute or KB-relative file path."},"context":{"type":"integer","description":"blame: surrounding lines of context."},"mode":{"type":"string","enum":["textVsText","currentVsText"],"description":"diff."},"left":{"type":"string","description":"diff: left-side text or snapshot label."},"right":{"type":"string","description":"diff: right-side text or snapshot label."},"against":{"type":"string","enum":["last-build","git-head"],"description":"diff_generated."},"kb":{"type":"string","description":"KB alias."}},"examples":[{"action":"history_list","name":"Customer"},{"action":"time_travel","name":"Customer","at":"2026-05-20T10:00:00Z"}]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":false}},
|
|
43
43
|
{"name":"genexus_io","description":"IO umbrella for assets, Object Text exchange, screenshots, OCR. action: asset_find|asset_read|asset_write | read_blob | export_part|import_part (single part) | export_kb_to_text|import_text_to_kb|validate_kb_text_files|delete_kb_objects (official GeneXus for Agents Object Text parity) | export_unified|screenshot_publish|ocr.","inputSchema":{"type":"object","required":["action"],"properties":{"action":{"type":"string","enum":["asset_find","asset_read","asset_write","read_blob","export_part","import_part","export_kb_to_text","import_text_to_kb","validate_kb_text_files","validate_text_in_memory","list_text_files","text_mirror_start","text_mirror_stop","text_mirror_status","text_mirror_catchup","text_mirror_set_references","delete_kb_objects","export_unified","screenshot_publish","ocr"],"description":"Asset, single-part, SDK text-tree, batch Object Text, screenshot, or OCR operation."},"path":{"type":"string","description":"asset/screenshot_publish/ocr: file path; Object Text import/validate may use a manifest directory."},"name":{"type":"string","description":"single object name or comma-separated selector; export_unified uses one object."},"targets":{"type":"array","items":{},"description":"Object Text selector array. Items may be names or {name,type} objects. Omit for export_kb_to_text to export the full indexed KB."},"outputPath":{"type":"string","description":"path"},"inputPath":{"type":"string","description":"import_part: source file; import_text_to_kb/validate_kb_text_files: manifest or directory."},"part":{"type":"string","description":"Object Text or part-exchange part name (e.g. Source, Rules, WebForm). For native format, part=all serializes authored textual parts into one sectioned .gx document."},"parts":{"type":"array","items":{"type":"string"},"description":"native export: explicit authored parts to include in one sectioned .gx document; part=all uses the safe default part set."},"format":{"type":"string","enum":["legacy","native"],"description":"Object Text export/import format. legacy preserves .gxtext compatibility; native creates the SDK text tree under src/ and ref/ without GX4A DLLs."},"mode":{"type":"string","enum":["all","newAndModified","newOnly"],"description":"native export mode. all writes every selected object; newAndModified uses the SDK/index version token; newOnly keeps existing files."},"includeDependencies":{"type":"boolean","description":"native export/import: include Calls/Tables dependency closure under ref/."},"includeReferences":{"type":"boolean","description":"Alias of includeDependencies for native src/ref exchange."},"includeVisualParts":{"type":"boolean","description":"native export/import: include WebForm/Layout companions (.web.xml or .report.xml)."},"includeModuleMetadata":{"type":"boolean","default":true,"description":"native export: emit deterministic module.toml metadata for modules represented in src/ref; no package DLL is loaded."},"includeModulePackages":{"type":"boolean","description":"native export: copy matching official .opc reference packages from the selected GeneXus installation into ref/; defaults to includeDependencies and never copies DLLs."},"includeTableProjections":{"type":"boolean","description":"native export: emit official SDK Table structures under src/#tables for selected Transactions; opt-in because tables may be shared/derived."},"includeChildren":{"type":"boolean","default":true,"description":"filesystem parity: recurse into child directories or expand Module/Folder selectors recursively; default true."},"listOnly":{"type":"boolean","description":"filesystem parity: return the resolved plan without reading the SDK, writing files or mutating the KB."},"stopOnError":{"type":"boolean","description":"filesystem parity: stop after the first item-level error and report remaining work for a safe resume."},"skip":{"type":"integer","minimum":0,"description":"filesystem parity: skip this many deterministic planned items before processing; useful for resuming a large batch."},"indentString":{"type":"string","description":"native export: optional prefix applied to non-empty source lines inside the object body; omitted preserves source indentation."},"forceSave":{"type":"boolean","description":"text import: force the official WriteService persistence path even when the content is unchanged."},"rollbackOnFailure":{"type":"boolean","default":true,"description":"native multi-part import: restore parts already written when a later SDK part write fails; reports reconciliationRequired if a prior snapshot cannot be read or restored."},"importMissingReferences":{"type":"boolean","description":"native import: include reference/dependency files when importing a tree."},"ignore":{"type":"array","items":{"type":"string"},"description":"list_text_files/validate_text_in_memory: relative file or directory prefixes to ignore; batch KB actions also accept object selectors."},"intervalMs":{"type":"integer","minimum":250,"description":"text_mirror_start: debounce/poll interval in milliseconds (250-600000)."},"initialSync":{"type":"boolean","description":"text_mirror_start: schedule a full catch-up immediately after start."},"full":{"type":"boolean","description":"text_mirror_catchup: reconcile the complete indexed KB instead of only queued changes."},"enabled":{"type":"boolean","description":"text_mirror_set_references: enable/disable reference export."},"type":{"type":"string","description":"Object type disambiguator/filter."},"module":{"type":"string","description":"Object Text module filter."},"pathPrefix":{"type":"string","description":"Object Text KB object-path prefix filter."},"overwrite":{"type":"boolean","description":"replace file"},"confirm":{"type":"boolean","description":"delete_kb_objects: required for a real delete; dryRun remains non-mutating."},"dryRun":{"type":"boolean","description":"Object Text import/delete preview without persisting changes."},"async":{"type":"boolean","description":"Run a batch Object Text operation as a cancellable background job when supported."},"pattern":{"type":"string","description":"asset_find: glob pattern."},"relativeRoot":{"type":"string","description":"asset_find: root for relative paths."},"limit":{"type":"integer","description":"asset_find/Object Text: max results."},"includeContent":{"type":"boolean","description":"asset_find: inline file content."},"maxBytes":{"type":"integer","description":"inline limit"},"includeBase64":{"type":"boolean","description":"include Base64 response"},"contentBase64":{"type":"string","description":"asset_write: base64-encoded file content."},"kb":{"type":"string","description":"KB alias."}},"examples":[{"action":"export_kb_to_text","outputPath":"C:\\tmp\\customer-text","targets":[{"name":"Customer","type":"Transaction"}]},{"action":"validate_kb_text_files","inputPath":"C:\\tmp\\customer-text"},{"action":"delete_kb_objects","targets":["Procedure:OldProc"],"dryRun":true}]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false}},
|
|
44
|
-
{"name":"genexus_variable","description":"Variables CRUD. add accepts varName or variables[] batch; modify changes type atomically. basedOn binds a Domain by native SDK identity. objectType=BusinessComponent with objectName+module binds a modular BC by EntityKey/GUID and verifies it after save. length/decimals override size; collection=true declares a collection; untyped add inherits a same-named attribute. dryRun validates and previews without mutation; async returns an operationId.","inputSchema":{"type":"object","required":["action","name"],"properties":{"action":{"type":"string","enum":["add","delete","modify"],"description":"Variable-part operation to add, delete, or modify a variable."},"name":{"type":"string"},"varName":{"type":"string","description":"Single-variable form (add/delete/modify). For batch add use variables[] instead."},"variables":{"type":"array","description":"Batch add only: one object per variable — {varName, typeName?, length?, decimals?, collection?}. Added before a single save.","items":{"type":"object","required":["varName"],"properties":{"varName":{"type":"string"},"typeName":{"type":"string"},"length":{"type":"integer"},"decimals":{"type":"integer"},"collection":{"type":"boolean"},"basedOn":{"type":"string","description":"Domain name; native SDK reference."}}}},"typeName":{"type":"string","description":"Primitive (Character/Numeric/VarChar/Date/...), SDT/BC/Domain name, or WebSession. VarChar keeps VARCHAR semantics."},"objectType":{"type":"string","enum":["BusinessComponent"],"description":"add/modify: resolve an object-backed variable natively instead of interpreting typeName as a Domain."},"objectName":{"type":"string","description":"Business Component Transaction name, without module when module is passed separately."},"module":{"type":"string","description":"Module owning objectName. Required to disambiguate modular Business Components."},"expectedVersion":{"type":"string","description":"Optimistic-concurrency token for an object-backed add/modify. Stale state returns VersionConflict before mutation."},"length":{"type":"integer","description":"add/modify optional: overrides the length parsed from typeName."},"decimals":{"type":"integer","description":"add/modify optional: overrides decimals parsed from typeName."},"collection":{"type":"boolean","description":"add/modify optional: declare the variable as a collection."},"basedOn":{"type":"string","description":"modify optional: Domain."},"dryRun":{"type":"boolean","default":false,"description":"Validate and return the typed diff without changing any object, Attribute, hash, or version."},"validationMode":{"type":"string","enum":["specify"],"description":"Explicitly run the inline Specify pass after a legacy variable write. Never runs unless requested."},"rollbackOnFailure":{"type":"boolean","default":true,"description":"Object-backed variables always snapshot the complete owner and restore it on save/re-read divergence."},"async":{"type":"boolean","description":"Run as a background job. Result returns operationId/job_id for genexus_lifecycle polling."},"estimated_seconds":{"type":"integer","description":"When async=true, expected runtime used for progress/job metadata (default 30)."},"kb":{"type":"string","description":"KB alias."}},"examples":[{"action":"add","name":"MyPanel","varName":"&Choice","typeName":"Numeric"},{"action":"add","name":"MyProc","varName":"&OrderRecord","objectType":"BusinessComponent","objectName":"OrderRecord","module":"Operations","dryRun":true},{"action":"add","name":"MyProc","variables":[{"varName":"&ApiKey","typeName":"VarChar","length":80},{"varName":"&CmdNro","typeName":"Numeric","length":9}]},{"action":"delete","name":"MyPanel","varName":"&OldVar"}]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false}},
|
|
44
|
+
{"name":"genexus_variable","description":"Variables CRUD. add accepts varName or variables[] batch; modify changes type atomically. basedOn binds a Domain by native SDK identity. objectType=BusinessComponent with objectName+module binds a modular BC by EntityKey/GUID and verifies it after save. length/decimals override size; collection=true declares a collection; untyped add inherits a same-named attribute. dryRun validates and previews without mutation; async returns an operationId.","inputSchema":{"type":"object","required":["action","name"],"properties":{"action":{"type":"string","enum":["add","delete","modify"],"description":"Variable-part operation to add, delete, or modify a variable."},"name":{"type":"string"},"varName":{"type":"string","description":"Single-variable form (add/delete/modify). For batch add use variables[] instead."},"variables":{"type":"array","description":"Batch add only: one object per variable — {varName, typeName?, length?, decimals?, collection?}. Added before a single save.","items":{"type":"object","required":["varName"],"properties":{"varName":{"type":"string"},"typeName":{"type":"string"},"length":{"type":"integer"},"decimals":{"type":"integer"},"collection":{"type":"boolean"},"basedOn":{"type":"string","description":"Domain name; native SDK reference."}}}},"typeName":{"type":"string","description":"Primitive (Character/Numeric/VarChar/Date/...), SDT/BC/Domain name, or WebSession. VarChar keeps VARCHAR semantics."},"newTypeName":{"type":"string","description":"modify alias for the replacement type; accepted alongside typeName."},"dataType":{"type":"string","description":"modify alias for the replacement type; accepted alongside typeName."},"objectType":{"type":"string","enum":["BusinessComponent"],"description":"add/modify: resolve an object-backed variable natively instead of interpreting typeName as a Domain."},"objectName":{"type":"string","description":"Business Component Transaction name, without module when module is passed separately."},"module":{"type":"string","description":"Module owning objectName. Required to disambiguate modular Business Components."},"expectedVersion":{"type":"string","description":"Optimistic-concurrency token for an object-backed add/modify. Stale state returns VersionConflict before mutation."},"length":{"type":"integer","description":"add/modify optional: overrides the length parsed from typeName."},"decimals":{"type":"integer","description":"add/modify optional: overrides decimals parsed from typeName."},"collection":{"type":"boolean","description":"add/modify optional: declare the variable as a collection."},"basedOn":{"type":"string","description":"modify optional: Domain."},"dryRun":{"type":"boolean","default":false,"description":"Validate and return the typed diff without changing any object, Attribute, hash, or version."},"validationMode":{"type":"string","enum":["specify"],"description":"Explicitly run the inline Specify pass after a legacy variable write. Never runs unless requested."},"rollbackOnFailure":{"type":"boolean","default":true,"description":"Object-backed variables always snapshot the complete owner and restore it on save/re-read divergence."},"async":{"type":"boolean","description":"Run as a background job. Result returns operationId/job_id for genexus_lifecycle polling."},"estimated_seconds":{"type":"integer","description":"When async=true, expected runtime used for progress/job metadata (default 30)."},"kb":{"type":"string","description":"KB alias."}},"examples":[{"action":"add","name":"MyPanel","varName":"&Choice","typeName":"Numeric"},{"action":"add","name":"MyProc","varName":"&OrderRecord","objectType":"BusinessComponent","objectName":"OrderRecord","module":"Operations","dryRun":true},{"action":"add","name":"MyProc","variables":[{"varName":"&ApiKey","typeName":"VarChar","length":80},{"varName":"&CmdNro","typeName":"Numeric","length":9}]},{"action":"delete","name":"MyPanel","varName":"&OldVar"}]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false}},
|
|
45
45
|
{"name":"genexus_telemetry","description":"Observability umbrella. action: executions (recent invocations) | watch_event (ops mentioning an event) | friction_append|friction_tail (.gx/friction.jsonl) | learning_report (aggregate friction) | logs (worker_debug.log tail) | profile_analyze|profile_hotspots|profile_correlate (GeneXus profiler XML).","inputSchema":{"type":"object","required":["action"],"properties":{"action":{"type":"string","enum":["executions","watch_event","friction_append","friction_tail","learning_report","logs","profile_analyze","profile_hotspots","profile_correlate"],"description":"Telemetry, profiling, or friction-log operation to perform."},"target":{"type":"string","description":"executions/watch_event: object name to filter."},"event":{"type":"string","description":"watch_event: event name to match in operation payload."},"last":{"type":"integer","description":"executions/watch_event: max results."},"tool":{"type":"string","description":"friction_append: tool name that produced the friction entry."},"message":{"type":"string","description":"friction_append: description of the friction encountered."},"severity":{"type":"string","enum":["info","warn","error","critical"],"description":"friction_append: severity level."},"n":{"type":"integer","description":"friction_tail: number of recent lines to return."},"since":{"type":"string","description":"learning_report/logs: ISO-8601 start time filter."},"until":{"type":"string","description":"learning_report: ISO-8601 end time filter."},"tail":{"type":"integer","description":"logs: number of tail lines from worker_debug.log."},"filterCorrelation":{"type":"string","description":"logs: filter by correlation/operation ID."},"grep":{"type":"string","description":"logs: substring filter on log lines."},"path":{"type":"string","description":"profile_*: path to the GeneXus profiler XML file."},"top":{"type":"integer","description":"profile_hotspots: top-N hottest procedures to return."},"kb":{"type":"string","description":"KB alias."}},"examples":[{"action":"executions"},{"action":"friction_tail","n":20}]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false}},
|
|
46
|
-
{"name":"genexus_create","description":"Creation. action: object (Transaction/Procedure/WebPanel/SDT/API/Domain/Dashboard/Folder/Module; type='API' scaffolds a REST API object with one HTTP-verb block per object; type='Folder'/'Module' create containers; folder/module places the new object there; SDT and Transaction take optional firstItem/firstItemType; Domain takes dataType+length or enumValues; NOT WWP — use genexus_apply_pattern) | popup (popup WebPanel with Form type='layout' body) | sd_panel_create|sd_panel_inspect|sd_panel_edit | save_as (clone parts) | scaffold|translate|sample (forge) | template (kpi_header|empty_state|confirm_dialog) | object_atomic (issue #62: all-or-nothing create/update of an object with variables[], rules[], parms[], properties{} and source in ONE validated call — pre-validates every field before the first save, composes the SDK write primitives, compensates on failure, dryRun previews, validate=true runs the inline Specify pass, update mode guards concurrent writes via expectedVersion). | curl_procedure imports a REST-consumer Procedure from a curl command through the GeneXus SDK.","inputSchema":{"type":"object","required":[
|
|
46
|
+
{"name":"genexus_create","description":"Creation. action: object (Transaction/Procedure/WebPanel/SDT/API/Domain/Dashboard/Folder/Module; type='API' scaffolds a REST API object with one HTTP-verb block per object; type='Folder'/'Module' create containers; folder/module places the new object there; SDT and Transaction take optional firstItem/firstItemType; Domain takes dataType+length or enumValues; NOT WWP — use genexus_apply_pattern) | popup (popup WebPanel with Form type='layout' body) | sd_panel_create|sd_panel_inspect|sd_panel_edit | save_as (clone parts) | scaffold|translate|sample (forge) | template (kpi_header|empty_state|confirm_dialog) | object_atomic (issue #62: all-or-nothing create/update of an object with variables[], rules[], parms[], properties{} and source in ONE validated call — pre-validates every field before the first save, composes the SDK write primitives, compensates on failure, dryRun previews, validate=true runs the inline Specify pass, update mode guards concurrent writes via expectedVersion). | curl_procedure imports a REST-consumer Procedure from a curl command through the GeneXus SDK.","inputSchema":{"type":"object","required":[],"properties":{"action":{"type":"string","enum":["object","object_atomic","popup","sd_panel_create","sd_panel_inspect","sd_panel_edit","save_as","scaffold","translate","sample","template","curl_procedure"],"description":"Object-creation or scaffold operation to perform."},"curl":{"type":"string","description":"curl_procedure: the curl command to import as a Procedure."},"type":{"type":"string","description":"Object type to create (Transaction, Procedure, WebPanel, SDT, API, Domain, Dashboard, Folder, Module)."},"objectType":{"type":"string","description":"Legacy alias for type when creating an object."},"name":{"type":"string","description":"Name of the object to create, clone, or update."},"newName":{"type":"string","description":"save_as."},"description":{"type":"string","description":"Human-readable description / title of the object."},"dataType":{"type":"string","description":"object Domain."},"length":{"type":"integer","description":"object Domain."},"decimals":{"type":"integer","description":"object Domain."},"signed":{"type":"boolean","description":"object Domain."},"basedOn":{"type":"string","description":"object Domain."},"enumValues":{"type":"array","items":{"type":"object"},"description":"object Domain enum."},"firstItem":{"type":"string","description":"object SDT/Transaction optional: name of the initial structure item/key attribute to seed (SDK requires >=1). Defaults to <ObjectName>Id for Transaction and Item1 for SDT."},"firstItemType":{"type":"string","description":"object SDT/Transaction optional: type of the seeded first item/key attribute (Character/Numeric/VarChar/…). Defaults to Numeric(4) for Transaction and VarChar for SDT."},"folder":{"type":"string","description":"object: Folder destination (created in Root, then moved+verified)."},"module":{"type":"string","description":"object: Module destination (created in Root, then moved+verified)."},"parentPath":{"type":"string","description":"object: folder/module destination (fallback when folder/module absent)."},"mode":{"type":"string","enum":["create","update","auto"],"description":"object_atomic: create (fail if exists), update (fail if missing), auto (default — create or update by existence)."},"variables":{"type":"array","items":{"type":"object","required":["varName"],"properties":{"varName":{"type":"string"},"typeName":{"type":"string"},"length":{"type":"integer"},"decimals":{"type":"integer"},"collection":{"type":"boolean"},"name":{"type":"string"},"basedOn":{"type":"string"}}},"description":"object_atomic: one object per variable — {varName, typeName?, length?, decimals?, collection?}. Validated before any save; errors are attributed to variables[N]."},"rules":{"type":"array","items":{"type":"string"},"description":"object_atomic: rule lines (e.g. \"Parm(in:&Id);\"). Send actual line breaks; literal backslash sequences \\r\\n, \\n, or \\r are rejected before the first save."},"parms":{"type":"array","items":{"type":"string"},"description":"object_atomic: parameter entries rendered into a Parm rule — bare names (\"&Id\") or prefixed (\"out:&Msg\")."},"source":{"type":"string","description":"object_atomic: Source part text. Send actual line breaks; literal backslash sequences \\r\\n, \\n, or \\r are rejected before the first save."},"properties":{"type":"object","description":"object_atomic: object-level properties applied via the genexus_properties path (propertyName → value)."},"expectedVersion":{"type":"string","description":"object_atomic update: optimistic concurrency token returned as `version` by a prior atomic create/update/read; a mismatch fails with ConcurrentModification instead of overwriting concurrent changes."},"validate":{"type":"boolean","description":"object_atomic: run the inline Specify pass (Spec+Gen) before confirming success. On failure with rollbackOnFailure=true, a freshly-created object is deleted so the operation stays all-or-nothing."},"validationMode":{"type":"string","enum":["specify"],"description":"Issue #60: with action=object, run the inline Specify pass (Spec+Gen, no Compile) after creation, returning structured spc*/gen* diagnostics in the same call. Combines with rollbackOnFailure."},"rollbackOnFailure":{"type":"boolean","description":"Issue #60: with action=object and validationMode=specify, roll back the created object when the specify pass reports errors. A fresh object has no pre-write snapshot, so rollback reports rolledBack=false — delete it via genexus_delete_object if spec fails."},"spec":{"type":"object","description":"popup."},"part":{"type":"string","description":"sd_panel_edit/template."},"content":{"type":"string","description":"sd_panel_edit/scaffold/translate."},"includePatternInstance":{"type":"boolean","description":"save_as."},"overwrite":{"type":"boolean","description":"save_as."},"dryRun":{"type":"boolean","description":"popup/save_as/template/object."},"template":{"type":"string","enum":["kpi_header","empty_state","confirm_dialog"],"description":"template."},"args":{"type":"object","description":"template."},"kb":{"type":"string","description":"KB alias."},"baseVersion":{"type":"string","description":"Optimistic concurrency versionToken for atomic create/update."},"updateExisting":{"type":"boolean","default":false,"description":"object_atomic: allow updating existing object if it already exists."}},"examples":[{"action":"object","name":"NewPanel","type":"WebPanel"},{"action":"object","name":"CustomerApi","type":"API"},{"action":"popup","name":"MyPopup","spec":{"host":"Customer"}}]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false}},
|
|
47
47
|
{"name":"genexus_memory","description":"Per-KB fact store. action: save (fact required; optional target/type/tags; dedups on identical fact+object, bumping a hit count) | recall (filter by target/type/tags — ANY match; no filter returns all) | list (all, newest first) | forget (tombstone by id) | promote (lift a friction-log message into a memory, tagged 'friction') | consolidate (dreaming — merge redundant/overlapping facts within scope; dryRun=true previews, dryRun=false compacts memory.jsonl). Persisted to .gx/memory/memory.jsonl.","inputSchema":{"type":"object","required":["action"],"properties":{"action":{"type":"string","enum":["save","recall","list","forget","promote","consolidate"],"description":"Persistent agent-memory operation to perform."},"fact":{"type":"string","description":"save: the fact to remember."},"target":{"type":"string","description":"object name this memory is about."},"type":{"type":"string","description":"object type this memory is about."},"tags":{"type":"array","items":{"type":"string"},"description":"labels for filtering."},"id":{"type":"string","description":"forget: memory id to tombstone."},"message":{"type":"string","description":"promote: friction text to promote into a memory."},"dryRun":{"type":"boolean","description":"consolidate: true previews proposed merges without writing; false (default) applies and compacts memory.jsonl."},"kb":{"type":"string","description":"KB alias."}},"additionalProperties":false,"examples":[{"action":"save","fact":"Customer.Email must be unique","target":"Customer","type":"Transaction","tags":["validation"]},{"action":"recall","target":"Customer"},{"action":"consolidate","dryRun":true}]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false}},
|
|
48
48
|
{"name":"genexus_transfer","description":"Real XPZ export/import over the SDK's IKnowledgeManagerService — dependency-aware, IDE Export/Import parity (NOT the filesystem copy genexus_io/kb_import do). action=export (targets[]+outputFile; includeDependencies=true exports transitive closure) | inspect (explore an .xpz, read-only) | import (apply into KB; dryRun defaults true=preview via ExploreExport; dryRun=false requires confirm=true).","inputSchema":{"type":"object","required":["action"],"properties":{"action":{"type":"string","enum":["export","inspect","import"],"description":"XPZ export, inspection, or import operation to perform."},"targets":{"type":"array","items":{"type":"string"},"description":"export: object names to export."},"outputFile":{"type":"string","description":"export: absolute .xpz output path."},"includeDependencies":{"type":"boolean","description":"export: compute transitive dependency closure (Calls, Tables) and export all referenced objects.","default":false},"file":{"type":"string","description":"inspect/import: absolute .xpz path."},"type":{"type":"string","description":"export: disambiguate object type."},"dryRun":{"type":"boolean","description":"import: true (default) previews; false applies (needs confirm)."},"confirm":{"type":"boolean","description":"import with dryRun=false: required."},"kb":{"type":"string","description":"KB alias."}},"examples":[{"action":"export","targets":["Customer"],"outputFile":"C:\\tmp\\cust.xpz"},{"action":"export","targets":["Customer"],"outputFile":"C:\\tmp\\cust_full.xpz","includeDependencies":true},{"action":"inspect","file":"C:\\tmp\\cust.xpz"}]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":false}},
|
|
49
49
|
{"name":"genexus_deploy","description":"Deploy application over the SDK. action=list_targets (read-only, default) enumerates deployment target types (IDeploymentTargetService); action=deploy (destructive, confirm=true) runs IDeploymentService.Deploy(model).","inputSchema":{"type":"object","properties":{"action":{"type":"string","enum":["list_targets","deploy"],"description":"Deployment-target or deployment execution operation to perform."},"confirm":{"type":"boolean","description":"deploy: required (builds + ships the app)."},"kb":{"type":"string","description":"KB alias."}},"examples":[{"action":"list_targets"},{"action":"deploy","confirm":true}]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":false}},
|
|
Binary file
|