@ebowwa/mcp-nm 2.0.2 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -13640,10 +13640,13 @@ class StdioServerTransport {
13640
13640
  // src/index.ts
13641
13641
  import { exec } from "child_process";
13642
13642
  import { promisify } from "util";
13643
+ import * as fs from "fs";
13644
+ import * as path from "path";
13645
+ import * as os from "os";
13643
13646
  var execAsync = promisify(exec);
13644
13647
  var server = new Server({
13645
13648
  name: "@ebowwa/mcp-nm",
13646
- version: "2.0.0"
13649
+ version: "2.1.0"
13647
13650
  }, {
13648
13651
  capabilities: {
13649
13652
  tools: {}
@@ -14977,6 +14980,953 @@ async function handleHexEditor(args) {
14977
14980
  throw new Error(`Hex editor failed: ${error2 instanceof Error ? error2.message : error2}`);
14978
14981
  }
14979
14982
  }
14983
+ function isMacOS() {
14984
+ return process.platform === "darwin";
14985
+ }
14986
+ async function handleCodesignInfo(args) {
14987
+ if (!isMacOS()) {
14988
+ return {
14989
+ content: [{
14990
+ type: "text",
14991
+ text: "Error: Code signing tools are only available on macOS. This tool requires the 'codesign' utility."
14992
+ }],
14993
+ isError: true
14994
+ };
14995
+ }
14996
+ try {
14997
+ const results = [];
14998
+ results.push(`Code Signature Info: ${args.filePath}`);
14999
+ results.push("");
15000
+ const { stdout: fileInfo } = await execAsync(`file "${args.filePath}"`);
15001
+ if (!fileInfo.toLowerCase().includes("mach-o")) {
15002
+ results.push("Warning: File does not appear to be a Mach-O binary");
15003
+ results.push(`File type: ${fileInfo.trim()}`);
15004
+ }
15005
+ try {
15006
+ const { stdout: signInfo } = await execAsync(`codesign -dv "${args.filePath}" 2>&1`);
15007
+ results.push("Signature Details:");
15008
+ results.push(signInfo.split(`
15009
+ `).map((line) => ` ${line}`).join(`
15010
+ `));
15011
+ } catch (e) {
15012
+ const output = e instanceof Error ? e.message : String(e);
15013
+ if (output.includes("no signature") || output.includes("code object is not signed")) {
15014
+ results.push("Status: NOT SIGNED");
15015
+ results.push(" The binary has no code signature");
15016
+ } else {
15017
+ results.push(`Signature check: ${output}`);
15018
+ }
15019
+ }
15020
+ try {
15021
+ await execAsync(`codesign -v "${args.filePath}" 2>&1`);
15022
+ results.push("");
15023
+ results.push("Validity: VALID - Signature is intact");
15024
+ } catch (e) {
15025
+ const output = e instanceof Error ? e.message : String(e);
15026
+ if (output.includes("not signed")) {
15027
+ results.push("");
15028
+ results.push("Validity: NOT SIGNED");
15029
+ } else {
15030
+ results.push("");
15031
+ results.push(`Validity: INVALID - ${output}`);
15032
+ }
15033
+ }
15034
+ try {
15035
+ const { stdout: reqs } = await execAsync(`codesign -dr - "${args.filePath}" 2>&1`);
15036
+ if (reqs.trim() && !reqs.includes("no signature")) {
15037
+ results.push("");
15038
+ results.push("Designated Requirements:");
15039
+ results.push(reqs.split(`
15040
+ `).map((line) => ` ${line}`).join(`
15041
+ `));
15042
+ }
15043
+ } catch {}
15044
+ return { content: [{ type: "text", text: results.join(`
15045
+ `) }] };
15046
+ } catch (error2) {
15047
+ return {
15048
+ content: [{ type: "text", text: `Error: ${error2 instanceof Error ? error2.message : String(error2)}` }],
15049
+ isError: true
15050
+ };
15051
+ }
15052
+ }
15053
+ async function handleCodesignRemove(args) {
15054
+ if (!isMacOS()) {
15055
+ return {
15056
+ content: [{
15057
+ type: "text",
15058
+ text: "Error: Code signing tools are only available on macOS."
15059
+ }],
15060
+ isError: true
15061
+ };
15062
+ }
15063
+ const createBackup = args.createBackup !== false;
15064
+ try {
15065
+ const results = [];
15066
+ results.push(`Remove Code Signature: ${args.filePath}`);
15067
+ results.push("");
15068
+ if (createBackup) {
15069
+ const backupPath = `${args.filePath}.bak`;
15070
+ await execAsync(`cp "${args.filePath}" "${backupPath}"`);
15071
+ results.push(`Backup created: ${backupPath}`);
15072
+ }
15073
+ try {
15074
+ const { stdout: signInfo } = await execAsync(`codesign -dv "${args.filePath}" 2>&1`);
15075
+ results.push(`Previous signature: ${signInfo.split(`
15076
+ `)[0] || "signed"}`);
15077
+ } catch {
15078
+ results.push("Previous signature: not signed or invalid");
15079
+ }
15080
+ try {
15081
+ await execAsync(`codesign --remove-signature "${args.filePath}"`);
15082
+ results.push("Status: SUCCESS - Code signature removed");
15083
+ } catch (e) {
15084
+ const output = e instanceof Error ? e.message : String(e);
15085
+ if (output.includes("no signature")) {
15086
+ results.push("Status: NO ACTION - Binary was not signed");
15087
+ } else {
15088
+ throw new Error(`Failed to remove signature: ${output}`);
15089
+ }
15090
+ }
15091
+ try {
15092
+ await execAsync(`codesign -v "${args.filePath}" 2>&1`);
15093
+ results.push("Warning: Signature still present after removal");
15094
+ } catch (e) {
15095
+ if (e instanceof Error && e.message.includes("not signed")) {
15096
+ results.push("Verification: Confirmed - Binary is now unsigned");
15097
+ }
15098
+ }
15099
+ return { content: [{ type: "text", text: results.join(`
15100
+ `) }] };
15101
+ } catch (error2) {
15102
+ return {
15103
+ content: [{ type: "text", text: `Error: ${error2 instanceof Error ? error2.message : String(error2)}` }],
15104
+ isError: true
15105
+ };
15106
+ }
15107
+ }
15108
+ async function handleCodesignSign(args) {
15109
+ if (!isMacOS()) {
15110
+ return {
15111
+ content: [{
15112
+ type: "text",
15113
+ text: "Error: Code signing tools are only available on macOS."
15114
+ }],
15115
+ isError: true
15116
+ };
15117
+ }
15118
+ const force = args.force !== false;
15119
+ const createBackup = args.createBackup === true;
15120
+ const deep = args.deep === true;
15121
+ const certificate = args.certificate || "-";
15122
+ try {
15123
+ const results = [];
15124
+ results.push(`Sign Binary: ${args.filePath}`);
15125
+ results.push("");
15126
+ if (createBackup) {
15127
+ const backupPath = `${args.filePath}.bak`;
15128
+ await execAsync(`cp "${args.filePath}" "${backupPath}"`);
15129
+ results.push(`Backup created: ${backupPath}`);
15130
+ }
15131
+ const forceFlag = force ? "--force" : "";
15132
+ const deepFlag = deep ? "--deep" : "";
15133
+ const optionsFlag = args.options ? `--options ${args.options}` : "";
15134
+ const cmd = `codesign -s ${certificate} ${forceFlag} ${deepFlag} ${optionsFlag} "${args.filePath}"`.replace(/\s+/g, " ").trim();
15135
+ results.push(`Command: ${cmd}`);
15136
+ results.push(`Signing with: ${certificate === "-" ? "ad-hoc signature" : certificate}`);
15137
+ await execAsync(cmd);
15138
+ results.push("Status: SUCCESS - Binary signed");
15139
+ try {
15140
+ await execAsync(`codesign -v "${args.filePath}" 2>&1`);
15141
+ results.push("Verification: VALID - Signature is intact");
15142
+ } catch (e) {
15143
+ results.push(`Verification: WARNING - ${e instanceof Error ? e.message : String(e)}`);
15144
+ }
15145
+ try {
15146
+ const { stdout: signInfo } = await execAsync(`codesign -dv "${args.filePath}" 2>&1`);
15147
+ const infoLine = signInfo.split(`
15148
+ `).find((l) => l.includes("Identifier") || l.includes("Authority"));
15149
+ if (infoLine) {
15150
+ results.push(`New signature: ${infoLine.trim()}`);
15151
+ }
15152
+ } catch {}
15153
+ return { content: [{ type: "text", text: results.join(`
15154
+ `) }] };
15155
+ } catch (error2) {
15156
+ return {
15157
+ content: [{ type: "text", text: `Error: ${error2 instanceof Error ? error2.message : String(error2)}` }],
15158
+ isError: true
15159
+ };
15160
+ }
15161
+ }
15162
+ async function handleQuarantineCheck(args) {
15163
+ if (!isMacOS()) {
15164
+ return {
15165
+ content: [{
15166
+ type: "text",
15167
+ text: "Error: Quarantine tools are only available on macOS."
15168
+ }],
15169
+ isError: true
15170
+ };
15171
+ }
15172
+ try {
15173
+ const results = [];
15174
+ results.push(`Quarantine Check: ${args.filePath}`);
15175
+ results.push("");
15176
+ try {
15177
+ const { stdout: quarantine } = await execAsync(`xattr -p com.apple.quarantine "${args.filePath}" 2>&1`);
15178
+ if (quarantine.trim()) {
15179
+ results.push("Status: QUARANTINED");
15180
+ results.push("");
15181
+ results.push("Quarantine data:");
15182
+ results.push(` ${quarantine.trim()}`);
15183
+ try {
15184
+ const { stdout: details } = await execAsync(`xattr -l "${args.filePath}" 2>&1`);
15185
+ const quarantineSection = details.split(`
15186
+ `).filter((l) => l.includes("quarantine") || l.includes("provenance"));
15187
+ if (quarantineSection.length > 0) {
15188
+ results.push("");
15189
+ results.push("Extended attributes:");
15190
+ quarantineSection.forEach((l) => results.push(` ${l}`));
15191
+ }
15192
+ } catch {}
15193
+ results.push("");
15194
+ results.push("Note: Quarantine prevents execution of downloaded files.");
15195
+ results.push("Use bin_quarantine_remove to allow execution.");
15196
+ } else {
15197
+ results.push("Status: NOT QUARANTINED");
15198
+ results.push("The file has no quarantine attribute.");
15199
+ }
15200
+ } catch (e) {
15201
+ const output = e instanceof Error ? e.message : String(e);
15202
+ if (output.includes("No such xattr") || output.includes("not found")) {
15203
+ results.push("Status: NOT QUARANTINED");
15204
+ results.push("The file has no quarantine attribute.");
15205
+ } else {
15206
+ throw new Error(`Failed to check quarantine: ${output}`);
15207
+ }
15208
+ }
15209
+ try {
15210
+ const { stdout: provenance } = await execAsync(`xattr -p com.apple.provenance "${args.filePath}" 2>&1`);
15211
+ if (provenance.trim()) {
15212
+ results.push("");
15213
+ results.push("Provenance: PRESENT");
15214
+ results.push(" File has provenance metadata (tracks download source)");
15215
+ }
15216
+ } catch {}
15217
+ return { content: [{ type: "text", text: results.join(`
15218
+ `) }] };
15219
+ } catch (error2) {
15220
+ return {
15221
+ content: [{ type: "text", text: `Error: ${error2 instanceof Error ? error2.message : String(error2)}` }],
15222
+ isError: true
15223
+ };
15224
+ }
15225
+ }
15226
+ async function handleQuarantineRemove(args) {
15227
+ if (!isMacOS()) {
15228
+ return {
15229
+ content: [{
15230
+ type: "text",
15231
+ text: "Error: Quarantine tools are only available on macOS."
15232
+ }],
15233
+ isError: true
15234
+ };
15235
+ }
15236
+ try {
15237
+ const results = [];
15238
+ results.push(`Remove Quarantine: ${args.filePath}`);
15239
+ results.push("");
15240
+ let removedAny = false;
15241
+ try {
15242
+ await execAsync(`xattr -d com.apple.quarantine "${args.filePath}" 2>&1`);
15243
+ results.push("Removed: com.apple.quarantine");
15244
+ removedAny = true;
15245
+ } catch (e) {
15246
+ const output = e instanceof Error ? e.message : String(e);
15247
+ if (output.includes("No such xattr") || output.includes("not found")) {
15248
+ results.push("Skipped: com.apple.quarantine (not present)");
15249
+ } else {
15250
+ results.push(`Warning: Could not remove quarantine - ${output}`);
15251
+ }
15252
+ }
15253
+ try {
15254
+ await execAsync(`xattr -d com.apple.provenance "${args.filePath}" 2>&1`);
15255
+ results.push("Removed: com.apple.provenance");
15256
+ removedAny = true;
15257
+ } catch {}
15258
+ try {
15259
+ await execAsync(`xattr -d com.apple.metadata:kMDItemWhereFroms "${args.filePath}" 2>&1`);
15260
+ results.push("Removed: com.apple.metadata:kMDItemWhereFroms");
15261
+ removedAny = true;
15262
+ } catch {}
15263
+ if (removedAny) {
15264
+ results.push("");
15265
+ results.push("Status: SUCCESS - Quarantine attributes removed");
15266
+ results.push("The file should now be able to execute without quarantine warnings.");
15267
+ } else {
15268
+ results.push("");
15269
+ results.push("Status: NO ACTION - No quarantine attributes found");
15270
+ }
15271
+ return { content: [{ type: "text", text: results.join(`
15272
+ `) }] };
15273
+ } catch (error2) {
15274
+ return {
15275
+ content: [{ type: "text", text: `Error: ${error2 instanceof Error ? error2.message : String(error2)}` }],
15276
+ isError: true
15277
+ };
15278
+ }
15279
+ }
15280
+ async function handleSafePatch(args) {
15281
+ if (!isMacOS()) {
15282
+ return {
15283
+ content: [{
15284
+ type: "text",
15285
+ text: "Error: Safe patching tools are only available on macOS."
15286
+ }],
15287
+ isError: true
15288
+ };
15289
+ }
15290
+ const createBackup = args.createBackup !== false;
15291
+ try {
15292
+ const results = [];
15293
+ results.push(`Safe Patch Workflow: ${args.filePath}`);
15294
+ results.push(` Offset: 0x${args.offset.toString(16)} (${args.offset})`);
15295
+ results.push(` Data: ${args.hexData}`);
15296
+ results.push("");
15297
+ if (createBackup) {
15298
+ const backupPath = `${args.filePath}.bak`;
15299
+ await execAsync(`cp "${args.filePath}" "${backupPath}"`);
15300
+ results.push(`[1/4] Backup created: ${backupPath}`);
15301
+ } else {
15302
+ results.push("[1/4] Backup: SKIPPED (createBackup=false)");
15303
+ }
15304
+ results.push("[2/4] Applying binary patch...");
15305
+ const hexBytes = args.hexData.replace(/\s+/g, "");
15306
+ const byteCount = hexBytes.length / 2;
15307
+ const patchCmd = `printf '${hexBytes}' | dd of="${args.filePath}" bs=1 seek=${args.offset} count=${byteCount} conv=notrunc 2>/dev/null`;
15308
+ await execAsync(patchCmd);
15309
+ results.push(` Patched ${byteCount} bytes at offset 0x${args.offset.toString(16)}`);
15310
+ results.push("[3/4] Removing old code signature...");
15311
+ try {
15312
+ await execAsync(`codesign --remove-signature "${args.filePath}" 2>&1`);
15313
+ results.push(" Old signature removed");
15314
+ } catch (e) {
15315
+ if (e instanceof Error && e.message.includes("no signature")) {
15316
+ results.push(" No previous signature to remove");
15317
+ } else {
15318
+ results.push(` Warning: ${e instanceof Error ? e.message : String(e)}`);
15319
+ }
15320
+ }
15321
+ results.push("[4/4] Applying ad-hoc signature...");
15322
+ await execAsync(`codesign --force --sign - "${args.filePath}"`);
15323
+ results.push(" Ad-hoc signature applied");
15324
+ results.push("[5/5] Removing quarantine attributes...");
15325
+ try {
15326
+ await execAsync(`xattr -d com.apple.quarantine "${args.filePath}" 2>&1`);
15327
+ results.push(" Quarantine attribute removed");
15328
+ } catch {
15329
+ results.push(" No quarantine attribute present");
15330
+ }
15331
+ try {
15332
+ await execAsync(`xattr -d com.apple.provenance "${args.filePath}" 2>&1`);
15333
+ results.push(" Provenance attribute removed");
15334
+ } catch {}
15335
+ results.push("");
15336
+ results.push("Verification:");
15337
+ try {
15338
+ await execAsync(`codesign -v "${args.filePath}" 2>&1`);
15339
+ results.push(" Code signature: VALID");
15340
+ } catch (e) {
15341
+ results.push(` Code signature: WARNING - ${e instanceof Error ? e.message : String(e)}`);
15342
+ }
15343
+ try {
15344
+ const { stdout: fileInfo } = await execAsync(`file "${args.filePath}"`);
15345
+ if (fileInfo.includes("executable")) {
15346
+ results.push(" File type: Executable");
15347
+ }
15348
+ } catch {}
15349
+ results.push("");
15350
+ results.push("Status: SUCCESS - Binary patched and ready to run");
15351
+ results.push("Note: The binary is now signed with an ad-hoc signature.");
15352
+ results.push(" Some apps may require proper code signing for full functionality.");
15353
+ return { content: [{ type: "text", text: results.join(`
15354
+ `) }] };
15355
+ } catch (error2) {
15356
+ return {
15357
+ content: [{ type: "text", text: `Error: ${error2 instanceof Error ? error2.message : String(error2)}` }],
15358
+ isError: true
15359
+ };
15360
+ }
15361
+ }
15362
+ async function handleBinVerify(args) {
15363
+ if (!isMacOS()) {
15364
+ return {
15365
+ content: [{
15366
+ type: "text",
15367
+ text: "Error: Binary verification tools are only available on macOS."
15368
+ }],
15369
+ isError: true
15370
+ };
15371
+ }
15372
+ try {
15373
+ const results = [];
15374
+ const issues = [];
15375
+ results.push(`Binary Verification: ${args.filePath}`);
15376
+ results.push("");
15377
+ let isMachO = false;
15378
+ try {
15379
+ const { stdout: fileInfo } = await execAsync(`file "${args.filePath}"`);
15380
+ results.push(`File type: ${fileInfo.trim()}`);
15381
+ isMachO = fileInfo.toLowerCase().includes("mach-o");
15382
+ } catch (e) {
15383
+ return {
15384
+ content: [{ type: "text", text: `Error: Cannot read file - ${e instanceof Error ? e.message : String(e)}` }],
15385
+ isError: true
15386
+ };
15387
+ }
15388
+ try {
15389
+ const { stdout: perms } = await execAsync(`ls -la "${args.filePath}"`);
15390
+ const permLine = perms.split(`
15391
+ `).find((l) => l.includes(args.filePath.split("/").pop() || ""));
15392
+ if (permLine) {
15393
+ results.push(`Permissions: ${permLine.split(/\s+/)[0]}`);
15394
+ if (!permLine.includes("x")) {
15395
+ issues.push("File is not executable (no execute permission)");
15396
+ }
15397
+ }
15398
+ } catch {
15399
+ results.push("Permissions: Unable to check");
15400
+ }
15401
+ results.push("");
15402
+ if (isMachO) {
15403
+ results.push("Code Signature:");
15404
+ try {
15405
+ const { stdout: signInfo } = await execAsync(`codesign -dv "${args.filePath}" 2>&1`);
15406
+ const authority = signInfo.split(`
15407
+ `).find((l) => l.includes("Authority"));
15408
+ if (authority) {
15409
+ results.push(` Status: SIGNED (${authority.split(":")[1]?.trim() || "unknown authority"})`);
15410
+ } else {
15411
+ results.push(" Status: SIGNED (ad-hoc or unknown)");
15412
+ }
15413
+ } catch (e) {
15414
+ const output = e instanceof Error ? e.message : String(e);
15415
+ if (output.includes("not signed")) {
15416
+ results.push(" Status: UNSIGNED");
15417
+ issues.push("Binary is not code signed");
15418
+ } else {
15419
+ results.push(` Status: INVALID - ${output}`);
15420
+ issues.push("Code signature is invalid");
15421
+ }
15422
+ }
15423
+ try {
15424
+ await execAsync(`codesign -v "${args.filePath}" 2>&1`);
15425
+ results.push(" Validity: VALID");
15426
+ } catch (e) {
15427
+ const output = e instanceof Error ? e.message : String(e);
15428
+ if (!output.includes("not signed")) {
15429
+ results.push(` Validity: INVALID - ${output}`);
15430
+ issues.push("Code signature verification failed");
15431
+ }
15432
+ }
15433
+ }
15434
+ results.push("");
15435
+ results.push("Quarantine:");
15436
+ try {
15437
+ const { stdout: quar } = await execAsync(`xattr -p com.apple.quarantine "${args.filePath}" 2>&1`);
15438
+ if (quar.trim()) {
15439
+ results.push(" Status: QUARANTINED");
15440
+ issues.push("File is quarantined and may be blocked from running");
15441
+ } else {
15442
+ results.push(" Status: NOT QUARANTINED");
15443
+ }
15444
+ } catch {
15445
+ results.push(" Status: NOT QUARANTINED");
15446
+ }
15447
+ if (isMachO) {
15448
+ results.push("");
15449
+ results.push("Architecture:");
15450
+ try {
15451
+ const { stdout: arch } = await execAsync(`lipo -info "${args.filePath}" 2>&1`);
15452
+ results.push(` ${arch.trim()}`);
15453
+ try {
15454
+ const { stdout: currentArch } = await execAsync(`uname -m`);
15455
+ if (!arch.includes(currentArch.trim()) && !arch.includes("universal")) {
15456
+ issues.push(`Binary may not be compatible with current architecture (${currentArch.trim()})`);
15457
+ }
15458
+ } catch {}
15459
+ } catch (e) {
15460
+ results.push(` Unable to determine: ${e instanceof Error ? e.message : String(e)}`);
15461
+ }
15462
+ }
15463
+ results.push("");
15464
+ results.push("=== SUMMARY ===");
15465
+ if (issues.length === 0) {
15466
+ results.push("Status: READY TO RUN");
15467
+ results.push("The binary should execute without issues.");
15468
+ } else {
15469
+ results.push("Status: ISSUES DETECTED");
15470
+ results.push("");
15471
+ results.push("Issues:");
15472
+ issues.forEach((issue2, i) => results.push(` ${i + 1}. ${issue2}`));
15473
+ results.push("");
15474
+ results.push("Suggested fixes:");
15475
+ if (issues.some((i) => i.includes("quarantined"))) {
15476
+ results.push(" - Run: xattr -d com.apple.quarantine <file>");
15477
+ }
15478
+ if (issues.some((i) => i.includes("not code signed") || i.includes("signature"))) {
15479
+ results.push(" - Run: codesign --force --sign - <file>");
15480
+ }
15481
+ if (issues.some((i) => i.includes("not executable"))) {
15482
+ results.push(" - Run: chmod +x <file>");
15483
+ }
15484
+ }
15485
+ return { content: [{ type: "text", text: results.join(`
15486
+ `) }] };
15487
+ } catch (error2) {
15488
+ return {
15489
+ content: [{ type: "text", text: `Error: ${error2 instanceof Error ? error2.message : String(error2)}` }],
15490
+ isError: true
15491
+ };
15492
+ }
15493
+ }
15494
+ var PATCH_DIR = path.join(os.homedir(), ".claude", "patches");
15495
+ var MANIFEST_PATH = path.join(PATCH_DIR, "manifest.json");
15496
+ var BACKUPS_DIR = path.join(PATCH_DIR, "backups");
15497
+ var MANIFEST_VERSION = "1.0.0";
15498
+ function ensurePatchDir() {
15499
+ if (!fs.existsSync(PATCH_DIR)) {
15500
+ fs.mkdirSync(PATCH_DIR, { recursive: true });
15501
+ }
15502
+ if (!fs.existsSync(BACKUPS_DIR)) {
15503
+ fs.mkdirSync(BACKUPS_DIR, { recursive: true });
15504
+ }
15505
+ }
15506
+ function loadManifest() {
15507
+ ensurePatchDir();
15508
+ if (fs.existsSync(MANIFEST_PATH)) {
15509
+ try {
15510
+ const data = fs.readFileSync(MANIFEST_PATH, "utf-8");
15511
+ return JSON.parse(data);
15512
+ } catch {}
15513
+ }
15514
+ return {
15515
+ version: MANIFEST_VERSION,
15516
+ createdAt: new Date().toISOString(),
15517
+ updatedAt: new Date().toISOString(),
15518
+ binaries: {}
15519
+ };
15520
+ }
15521
+ function saveManifest(manifest) {
15522
+ ensurePatchDir();
15523
+ manifest.updatedAt = new Date().toISOString();
15524
+ fs.writeFileSync(MANIFEST_PATH, JSON.stringify(manifest, null, 2));
15525
+ }
15526
+ async function getFileChecksum(filePath) {
15527
+ try {
15528
+ const { stdout } = await execAsync(`shasum -a 256 "${filePath}" | cut -d' ' -f1`);
15529
+ return stdout.trim();
15530
+ } catch {
15531
+ return "unknown";
15532
+ }
15533
+ }
15534
+ function readBytesAtOffset(filePath, offset, length) {
15535
+ const fd = fs.openSync(filePath, "r");
15536
+ const buffer = Buffer.alloc(length);
15537
+ fs.readSync(fd, buffer, 0, length, offset);
15538
+ fs.closeSync(fd);
15539
+ return buffer.toString("hex").match(/.{2}/g)?.join(" ").toUpperCase() || "";
15540
+ }
15541
+ function writeBytesAtOffset(filePath, offset, hexData) {
15542
+ const bytes = Buffer.from(hexData.replace(/\s+/g, ""), "hex");
15543
+ const fd = fs.openSync(filePath, "r+");
15544
+ fs.writeSync(fd, bytes, 0, bytes.length, offset);
15545
+ fs.closeSync(fd);
15546
+ }
15547
+ async function handlePatchRegister(args) {
15548
+ try {
15549
+ const results = [];
15550
+ results.push(`Register Patch: ${args.patchId}`);
15551
+ results.push(`Binary: ${args.filePath}`);
15552
+ results.push(`Offset: 0x${args.offset.toString(16)} (${args.offset})`);
15553
+ results.push("");
15554
+ if (!fs.existsSync(args.filePath)) {
15555
+ return {
15556
+ content: [{ type: "text", text: `Error: File not found: ${args.filePath}` }],
15557
+ isError: true
15558
+ };
15559
+ }
15560
+ const patchedBytes = args.patchedBytes.replace(/\s+/g, "").toUpperCase();
15561
+ const byteLength = patchedBytes.length / 2;
15562
+ let originalBytes = "";
15563
+ if (args.captureOriginal !== false) {
15564
+ try {
15565
+ originalBytes = readBytesAtOffset(args.filePath, args.offset, byteLength);
15566
+ results.push(`Original bytes: ${originalBytes}`);
15567
+ } catch (e) {
15568
+ return {
15569
+ content: [{ type: "text", text: `Error: Could not read original bytes - ${e instanceof Error ? e.message : String(e)}` }],
15570
+ isError: true
15571
+ };
15572
+ }
15573
+ }
15574
+ const backupFileName = `${path.basename(args.filePath)}.offset_${args.offset}.bin`;
15575
+ const backupPath = path.join(BACKUPS_DIR, backupFileName);
15576
+ if (originalBytes) {
15577
+ fs.writeFileSync(backupPath, Buffer.from(originalBytes.replace(/\s+/g, ""), "hex"));
15578
+ results.push(`Backup saved: ${backupPath}`);
15579
+ }
15580
+ const manifest = loadManifest();
15581
+ const checksum = await getFileChecksum(args.filePath);
15582
+ if (!manifest.binaries[args.filePath]) {
15583
+ manifest.binaries[args.filePath] = {
15584
+ binaryPath: args.filePath,
15585
+ binaryName: path.basename(args.filePath),
15586
+ lastPatchedChecksum: checksum,
15587
+ lastAppliedAt: new Date().toISOString(),
15588
+ patches: []
15589
+ };
15590
+ }
15591
+ const existingIndex = manifest.binaries[args.filePath].patches.findIndex((p) => p.id === args.patchId);
15592
+ const newPatch = {
15593
+ id: args.patchId,
15594
+ offset: args.offset,
15595
+ originalBytes: originalBytes || "UNKNOWN",
15596
+ patchedBytes: patchedBytes.match(/.{2}/g)?.join(" ") || patchedBytes,
15597
+ description: args.description,
15598
+ createdAt: new Date().toISOString()
15599
+ };
15600
+ if (existingIndex >= 0) {
15601
+ manifest.binaries[args.filePath].patches[existingIndex] = newPatch;
15602
+ results.push(`Updated existing patch: ${args.patchId}`);
15603
+ } else {
15604
+ manifest.binaries[args.filePath].patches.push(newPatch);
15605
+ results.push(`Registered new patch: ${args.patchId}`);
15606
+ }
15607
+ saveManifest(manifest);
15608
+ results.push("");
15609
+ results.push("Patch registered successfully!");
15610
+ results.push(`Manifest: ${MANIFEST_PATH}`);
15611
+ results.push("");
15612
+ results.push("To apply this patch, use: bin_patch_apply");
15613
+ return { content: [{ type: "text", text: results.join(`
15614
+ `) }] };
15615
+ } catch (error2) {
15616
+ return {
15617
+ content: [{ type: "text", text: `Error: ${error2 instanceof Error ? error2.message : String(error2)}` }],
15618
+ isError: true
15619
+ };
15620
+ }
15621
+ }
15622
+ async function handlePatchApply(args) {
15623
+ const isMac = isMacOS();
15624
+ const resign = args.resign !== false && isMac;
15625
+ const removeQuarantine = args.removeQuarantine !== false && isMac;
15626
+ try {
15627
+ const results = [];
15628
+ results.push(`Apply Patches: ${args.filePath}`);
15629
+ results.push("");
15630
+ const manifest = loadManifest();
15631
+ const record3 = manifest.binaries[args.filePath];
15632
+ if (!record3 || record3.patches.length === 0) {
15633
+ results.push("No registered patches found for this binary.");
15634
+ results.push("");
15635
+ results.push("To register a patch, use: bin_patch_register");
15636
+ return { content: [{ type: "text", text: results.join(`
15637
+ `) }] };
15638
+ }
15639
+ const currentChecksum = await getFileChecksum(args.filePath);
15640
+ results.push(`Current checksum: ${currentChecksum.substring(0, 16)}...`);
15641
+ results.push(`Last patched checksum: ${record3.lastPatchedChecksum.substring(0, 16)}...`);
15642
+ if (currentChecksum === record3.lastPatchedChecksum) {
15643
+ results.push("Status: Binary appears to already have patches applied.");
15644
+ results.push("Use force=true to re-apply anyway.");
15645
+ return { content: [{ type: "text", text: results.join(`
15646
+ `) }] };
15647
+ }
15648
+ results.push("Binary has been updated - applying patches...");
15649
+ results.push("");
15650
+ const backupPath = `${args.filePath}.prepatch`;
15651
+ fs.copyFileSync(args.filePath, backupPath);
15652
+ results.push(`Backup: ${backupPath}`);
15653
+ let appliedCount = 0;
15654
+ for (const patch of record3.patches) {
15655
+ try {
15656
+ results.push(`Applying: ${patch.id}`);
15657
+ results.push(` Offset: 0x${patch.offset.toString(16)}`);
15658
+ results.push(` Bytes: ${patch.patchedBytes}`);
15659
+ writeBytesAtOffset(args.filePath, patch.offset, patch.patchedBytes);
15660
+ appliedCount++;
15661
+ results.push(" Status: Applied");
15662
+ } catch (e) {
15663
+ results.push(` Status: FAILED - ${e instanceof Error ? e.message : String(e)}`);
15664
+ }
15665
+ }
15666
+ if (isMac && appliedCount > 0) {
15667
+ results.push("");
15668
+ if (resign) {
15669
+ results.push("Re-signing binary...");
15670
+ try {
15671
+ await execAsync(`codesign --remove-signature "${args.filePath}" 2>&1`);
15672
+ await execAsync(`codesign --force --sign - "${args.filePath}"`);
15673
+ results.push(" Status: Re-signed with ad-hoc signature");
15674
+ } catch (e) {
15675
+ results.push(` Warning: ${e instanceof Error ? e.message : String(e)}`);
15676
+ }
15677
+ }
15678
+ if (removeQuarantine) {
15679
+ results.push("Removing quarantine...");
15680
+ try {
15681
+ await execAsync(`xattr -d com.apple.quarantine "${args.filePath}" 2>&1`);
15682
+ await execAsync(`xattr -d com.apple.provenance "${args.filePath}" 2>&1`);
15683
+ results.push(" Status: Quarantine attributes removed");
15684
+ } catch {
15685
+ results.push(" Status: No quarantine to remove");
15686
+ }
15687
+ }
15688
+ }
15689
+ const newChecksum = await getFileChecksum(args.filePath);
15690
+ record3.lastPatchedChecksum = newChecksum;
15691
+ record3.lastAppliedAt = new Date().toISOString();
15692
+ saveManifest(manifest);
15693
+ results.push("");
15694
+ results.push(`=== SUMMARY ===`);
15695
+ results.push(`Patches applied: ${appliedCount}/${record3.patches.length}`);
15696
+ results.push(`New checksum: ${newChecksum.substring(0, 16)}...`);
15697
+ results.push("Binary is ready to use.");
15698
+ return { content: [{ type: "text", text: results.join(`
15699
+ `) }] };
15700
+ } catch (error2) {
15701
+ return {
15702
+ content: [{ type: "text", text: `Error: ${error2 instanceof Error ? error2.message : String(error2)}` }],
15703
+ isError: true
15704
+ };
15705
+ }
15706
+ }
15707
+ async function handlePatchVerify(args) {
15708
+ try {
15709
+ const results = [];
15710
+ results.push(`Verify Patches: ${args.filePath}`);
15711
+ results.push("");
15712
+ const manifest = loadManifest();
15713
+ const record3 = manifest.binaries[args.filePath];
15714
+ if (!record3 || record3.patches.length === 0) {
15715
+ results.push("No registered patches found for this binary.");
15716
+ return { content: [{ type: "text", text: results.join(`
15717
+ `) }] };
15718
+ }
15719
+ const currentChecksum = await getFileChecksum(args.filePath);
15720
+ results.push(`Current checksum: ${currentChecksum.substring(0, 16)}...`);
15721
+ results.push(`Expected checksum: ${record3.lastPatchedChecksum.substring(0, 16)}...`);
15722
+ results.push("");
15723
+ if (currentChecksum !== record3.lastPatchedChecksum) {
15724
+ results.push("⚠️ Binary has been UPDATED since last patch.");
15725
+ results.push(" Run bin_patch_apply to re-apply patches.");
15726
+ results.push("");
15727
+ } else {
15728
+ results.push("✓ Binary checksum matches patched version.");
15729
+ results.push("");
15730
+ }
15731
+ results.push("Patch Status:");
15732
+ let allApplied = true;
15733
+ for (const patch of record3.patches) {
15734
+ try {
15735
+ const byteLength = patch.patchedBytes.replace(/\s+/g, "").length / 2;
15736
+ const currentBytes = readBytesAtOffset(args.filePath, patch.offset, byteLength);
15737
+ const normalizedCurrent = currentBytes.replace(/\s+/g, "").toUpperCase();
15738
+ const normalizedPatched = patch.patchedBytes.replace(/\s+/g, "").toUpperCase();
15739
+ if (normalizedCurrent === normalizedPatched) {
15740
+ results.push(` ✓ ${patch.id}: APPLIED`);
15741
+ } else if (normalizedCurrent === patch.originalBytes.replace(/\s+/g, "").toUpperCase()) {
15742
+ results.push(` ✗ ${patch.id}: NOT APPLIED (original bytes present)`);
15743
+ allApplied = false;
15744
+ } else {
15745
+ results.push(` ? ${patch.id}: UNKNOWN (bytes don't match expected)`);
15746
+ results.push(` Current: ${currentBytes}`);
15747
+ results.push(` Expected: ${patch.patchedBytes}`);
15748
+ allApplied = false;
15749
+ }
15750
+ } catch (e) {
15751
+ results.push(` ✗ ${patch.id}: ERROR - ${e instanceof Error ? e.message : String(e)}`);
15752
+ allApplied = false;
15753
+ }
15754
+ }
15755
+ results.push("");
15756
+ if (allApplied && currentChecksum === record3.lastPatchedChecksum) {
15757
+ results.push("Status: All patches verified and applied.");
15758
+ } else if (!allApplied) {
15759
+ results.push("Status: Some patches need to be applied.");
15760
+ results.push("Action: Run bin_patch_apply");
15761
+ } else {
15762
+ results.push("Status: Binary may have been updated. Re-apply patches.");
15763
+ results.push("Action: Run bin_patch_apply");
15764
+ }
15765
+ return { content: [{ type: "text", text: results.join(`
15766
+ `) }] };
15767
+ } catch (error2) {
15768
+ return {
15769
+ content: [{ type: "text", text: `Error: ${error2 instanceof Error ? error2.message : String(error2)}` }],
15770
+ isError: true
15771
+ };
15772
+ }
15773
+ }
15774
+ async function handlePatchRestore(args) {
15775
+ const isMac = isMacOS();
15776
+ const resign = args.resign !== false && isMac;
15777
+ try {
15778
+ const results = [];
15779
+ results.push(`Restore Patches: ${args.filePath}`);
15780
+ results.push("");
15781
+ const manifest = loadManifest();
15782
+ const record3 = manifest.binaries[args.filePath];
15783
+ if (!record3 || record3.patches.length === 0) {
15784
+ results.push("No registered patches found for this binary.");
15785
+ return { content: [{ type: "text", text: results.join(`
15786
+ `) }] };
15787
+ }
15788
+ const patchesToRestore = args.patchId ? record3.patches.filter((p) => p.id === args.patchId) : record3.patches;
15789
+ if (patchesToRestore.length === 0) {
15790
+ results.push(`No patch found with ID: ${args.patchId}`);
15791
+ return { content: [{ type: "text", text: results.join(`
15792
+ `) }] };
15793
+ }
15794
+ const backupPath = `${args.filePath}.prerestore`;
15795
+ fs.copyFileSync(args.filePath, backupPath);
15796
+ results.push(`Backup: ${backupPath}`);
15797
+ results.push("");
15798
+ let restoredCount = 0;
15799
+ for (const patch of patchesToRestore) {
15800
+ if (patch.originalBytes === "UNKNOWN") {
15801
+ results.push(`${patch.id}: SKIPPED (no original bytes captured)`);
15802
+ continue;
15803
+ }
15804
+ try {
15805
+ results.push(`Restoring: ${patch.id}`);
15806
+ writeBytesAtOffset(args.filePath, patch.offset, patch.originalBytes);
15807
+ results.push(` Offset: 0x${patch.offset.toString(16)}`);
15808
+ results.push(` Bytes: ${patch.originalBytes}`);
15809
+ results.push(" Status: Restored");
15810
+ restoredCount++;
15811
+ } catch (e) {
15812
+ results.push(` Status: FAILED - ${e instanceof Error ? e.message : String(e)}`);
15813
+ }
15814
+ }
15815
+ if (isMac && restoredCount > 0 && resign) {
15816
+ results.push("");
15817
+ results.push("Re-signing binary...");
15818
+ try {
15819
+ await execAsync(`codesign --remove-signature "${args.filePath}" 2>&1`);
15820
+ await execAsync(`codesign --force --sign - "${args.filePath}"`);
15821
+ results.push(" Status: Re-signed with ad-hoc signature");
15822
+ } catch (e) {
15823
+ results.push(` Warning: ${e instanceof Error ? e.message : String(e)}`);
15824
+ }
15825
+ }
15826
+ const newChecksum = await getFileChecksum(args.filePath);
15827
+ record3.lastPatchedChecksum = newChecksum;
15828
+ saveManifest(manifest);
15829
+ results.push("");
15830
+ results.push(`Restored: ${restoredCount}/${patchesToRestore.length} patches`);
15831
+ return { content: [{ type: "text", text: results.join(`
15832
+ `) }] };
15833
+ } catch (error2) {
15834
+ return {
15835
+ content: [{ type: "text", text: `Error: ${error2 instanceof Error ? error2.message : String(error2)}` }],
15836
+ isError: true
15837
+ };
15838
+ }
15839
+ }
15840
+ async function handlePatchList(args) {
15841
+ try {
15842
+ const results = [];
15843
+ results.push("Patch Registry");
15844
+ results.push(`Manifest: ${MANIFEST_PATH}`);
15845
+ results.push("");
15846
+ const manifest = loadManifest();
15847
+ if (Object.keys(manifest.binaries).length === 0) {
15848
+ results.push("No patches registered.");
15849
+ results.push("");
15850
+ results.push("To register a patch, use: bin_patch_register");
15851
+ return { content: [{ type: "text", text: results.join(`
15852
+ `) }] };
15853
+ }
15854
+ const binariesToShow = args.filePath ? { [args.filePath]: manifest.binaries[args.filePath] } : manifest.binaries;
15855
+ for (const [binaryPath, record3] of Object.entries(binariesToShow)) {
15856
+ if (!record3)
15857
+ continue;
15858
+ results.push(`═══════════════════════════════════════════════════════════`);
15859
+ results.push(`Binary: ${binaryPath}`);
15860
+ results.push(`Name: ${record3.binaryName}`);
15861
+ results.push(`Patches: ${record3.patches.length}`);
15862
+ results.push(`Last Applied: ${record3.lastAppliedAt}`);
15863
+ results.push(`Checksum: ${record3.lastPatchedChecksum.substring(0, 16)}...`);
15864
+ results.push("");
15865
+ if (record3.patches.length > 0) {
15866
+ results.push("Registered Patches:");
15867
+ for (const patch of record3.patches) {
15868
+ results.push(` ┌─ ${patch.id} ─────────────────────────────────`);
15869
+ results.push(` │ Offset: 0x${patch.offset.toString(16)} (${patch.offset})`);
15870
+ results.push(` │ Original: ${patch.originalBytes}`);
15871
+ results.push(` │ Patched: ${patch.patchedBytes}`);
15872
+ results.push(` │ Description: ${patch.description}`);
15873
+ results.push(` │ Created: ${patch.createdAt}`);
15874
+ results.push(` └────────────────────────────────────────────`);
15875
+ }
15876
+ }
15877
+ results.push("");
15878
+ }
15879
+ return { content: [{ type: "text", text: results.join(`
15880
+ `) }] };
15881
+ } catch (error2) {
15882
+ return {
15883
+ content: [{ type: "text", text: `Error: ${error2 instanceof Error ? error2.message : String(error2)}` }],
15884
+ isError: true
15885
+ };
15886
+ }
15887
+ }
15888
+ async function handlePatchRemove(args) {
15889
+ try {
15890
+ const results = [];
15891
+ results.push(`Remove Patch: ${args.patchId}`);
15892
+ results.push("");
15893
+ const manifest = loadManifest();
15894
+ const record3 = manifest.binaries[args.filePath];
15895
+ if (!record3) {
15896
+ results.push("No patches registered for this binary.");
15897
+ return { content: [{ type: "text", text: results.join(`
15898
+ `) }] };
15899
+ }
15900
+ const index = record3.patches.findIndex((p) => p.id === args.patchId);
15901
+ if (index < 0) {
15902
+ results.push(`Patch not found: ${args.patchId}`);
15903
+ return { content: [{ type: "text", text: results.join(`
15904
+ `) }] };
15905
+ }
15906
+ const removed = record3.patches.splice(index, 1)[0];
15907
+ results.push("Removed patch:");
15908
+ results.push(` ID: ${removed.id}`);
15909
+ results.push(` Offset: 0x${removed.offset.toString(16)}`);
15910
+ results.push(` Description: ${removed.description}`);
15911
+ if (record3.patches.length === 0) {
15912
+ delete manifest.binaries[args.filePath];
15913
+ results.push("");
15914
+ results.push("No more patches for this binary - removed from registry.");
15915
+ }
15916
+ saveManifest(manifest);
15917
+ results.push("");
15918
+ results.push("Patch removed from registry.");
15919
+ results.push("Note: This does NOT undo the patch in the binary.");
15920
+ results.push("Use bin_patch_restore to restore original bytes.");
15921
+ return { content: [{ type: "text", text: results.join(`
15922
+ `) }] };
15923
+ } catch (error2) {
15924
+ return {
15925
+ content: [{ type: "text", text: `Error: ${error2 instanceof Error ? error2.message : String(error2)}` }],
15926
+ isError: true
15927
+ };
15928
+ }
15929
+ }
14980
15930
  var TOOLS = [
14981
15931
  {
14982
15932
  name: "nm_list_symbols",
@@ -15439,6 +16389,168 @@ var TOOLS = [
15439
16389
  },
15440
16390
  required: ["filePath", "offset", "length"]
15441
16391
  }
16392
+ },
16393
+ {
16394
+ name: "bin_codesign_info",
16395
+ description: "Show code signature details for a macOS binary (macOS only)",
16396
+ inputSchema: {
16397
+ type: "object",
16398
+ properties: {
16399
+ filePath: { type: "string", description: "Path to the binary file" }
16400
+ },
16401
+ required: ["filePath"]
16402
+ }
16403
+ },
16404
+ {
16405
+ name: "bin_codesign_remove",
16406
+ description: "Remove code signature from a macOS binary (DESTRUCTIVE - macOS only)",
16407
+ inputSchema: {
16408
+ type: "object",
16409
+ properties: {
16410
+ filePath: { type: "string", description: "Path to the binary file" },
16411
+ createBackup: { type: "boolean", description: "Create .bak backup (default: true)" }
16412
+ },
16413
+ required: ["filePath"]
16414
+ }
16415
+ },
16416
+ {
16417
+ name: "bin_codesign_sign",
16418
+ description: "Apply ad-hoc or certificate signature to a macOS binary (macOS only)",
16419
+ inputSchema: {
16420
+ type: "object",
16421
+ properties: {
16422
+ filePath: { type: "string", description: "Path to the binary file" },
16423
+ certificate: { type: "string", description: "Certificate identity (default: '-' for ad-hoc signature)" },
16424
+ force: { type: "boolean", description: "Force replace existing signature (default: true)" },
16425
+ createBackup: { type: "boolean", description: "Create .bak backup before signing" },
16426
+ deep: { type: "boolean", description: "Sign all nested code" },
16427
+ options: { type: "string", description: "Additional signing options (e.g., 'runtime' for hardened runtime)" }
16428
+ },
16429
+ required: ["filePath"]
16430
+ }
16431
+ },
16432
+ {
16433
+ name: "bin_quarantine_check",
16434
+ description: "Check quarantine status of a file on macOS (macOS only)",
16435
+ inputSchema: {
16436
+ type: "object",
16437
+ properties: {
16438
+ filePath: { type: "string", description: "Path to the file" }
16439
+ },
16440
+ required: ["filePath"]
16441
+ }
16442
+ },
16443
+ {
16444
+ name: "bin_quarantine_remove",
16445
+ description: "Remove quarantine attributes from a file on macOS (DESTRUCTIVE - macOS only)",
16446
+ inputSchema: {
16447
+ type: "object",
16448
+ properties: {
16449
+ filePath: { type: "string", description: "Path to the file" }
16450
+ },
16451
+ required: ["filePath"]
16452
+ }
16453
+ },
16454
+ {
16455
+ name: "bin_safe_patch",
16456
+ description: "Safe binary patching workflow for macOS: patch, remove signature, re-sign, remove quarantine (DESTRUCTIVE - macOS only)",
16457
+ inputSchema: {
16458
+ type: "object",
16459
+ properties: {
16460
+ filePath: { type: "string", description: "Path to the binary file" },
16461
+ offset: { type: "number", description: "Byte offset to patch" },
16462
+ hexData: { type: "string", description: "Hex bytes to write (e.g., '90 90 90')" },
16463
+ createBackup: { type: "boolean", description: "Create .bak backup (default: true)" }
16464
+ },
16465
+ required: ["filePath", "offset", "hexData"]
16466
+ }
16467
+ },
16468
+ {
16469
+ name: "bin_verify",
16470
+ description: "Verify if a macOS binary will run: check signature, quarantine, architecture (macOS only)",
16471
+ inputSchema: {
16472
+ type: "object",
16473
+ properties: {
16474
+ filePath: { type: "string", description: "Path to the binary file" }
16475
+ },
16476
+ required: ["filePath"]
16477
+ }
16478
+ },
16479
+ {
16480
+ name: "bin_patch_register",
16481
+ description: "Register a binary patch for persistence across updates. Captures original bytes and stores in manifest.",
16482
+ inputSchema: {
16483
+ type: "object",
16484
+ properties: {
16485
+ filePath: { type: "string", description: "Path to the binary file" },
16486
+ patchId: { type: "string", description: "Unique identifier for this patch (e.g., 'skip-permissions')" },
16487
+ offset: { type: "number", description: "Byte offset to patch" },
16488
+ patchedBytes: { type: "string", description: "Hex bytes to write (e.g., '90 90 90')" },
16489
+ description: { type: "string", description: "Description of what this patch does" },
16490
+ captureOriginal: { type: "boolean", description: "Capture original bytes (default: true)" }
16491
+ },
16492
+ required: ["filePath", "patchId", "offset", "patchedBytes", "description"]
16493
+ }
16494
+ },
16495
+ {
16496
+ name: "bin_patch_apply",
16497
+ description: "Apply all registered patches to a binary. Handles macOS re-signing and quarantine. Detects binary updates.",
16498
+ inputSchema: {
16499
+ type: "object",
16500
+ properties: {
16501
+ filePath: { type: "string", description: "Path to the binary file" },
16502
+ resign: { type: "boolean", description: "Re-sign binary after patching (macOS, default: true)" },
16503
+ removeQuarantine: { type: "boolean", description: "Remove quarantine after patching (macOS, default: true)" }
16504
+ },
16505
+ required: ["filePath"]
16506
+ }
16507
+ },
16508
+ {
16509
+ name: "bin_patch_verify",
16510
+ description: "Verify if registered patches are currently applied to a binary. Detects if binary was updated.",
16511
+ inputSchema: {
16512
+ type: "object",
16513
+ properties: {
16514
+ filePath: { type: "string", description: "Path to the binary file" }
16515
+ },
16516
+ required: ["filePath"]
16517
+ }
16518
+ },
16519
+ {
16520
+ name: "bin_patch_restore",
16521
+ description: "Restore original bytes for registered patches. Undoes patches in the binary.",
16522
+ inputSchema: {
16523
+ type: "object",
16524
+ properties: {
16525
+ filePath: { type: "string", description: "Path to the binary file" },
16526
+ patchId: { type: "string", description: "Specific patch to restore (optional - restores all if omitted)" },
16527
+ resign: { type: "boolean", description: "Re-sign binary after restoring (macOS, default: true)" }
16528
+ },
16529
+ required: ["filePath"]
16530
+ }
16531
+ },
16532
+ {
16533
+ name: "bin_patch_list",
16534
+ description: "List all registered patches in the manifest, optionally filtered by binary.",
16535
+ inputSchema: {
16536
+ type: "object",
16537
+ properties: {
16538
+ filePath: { type: "string", description: "Filter by binary path (optional)" }
16539
+ },
16540
+ required: []
16541
+ }
16542
+ },
16543
+ {
16544
+ name: "bin_patch_remove",
16545
+ description: "Remove a patch from the registry. Does NOT undo the patch in the binary.",
16546
+ inputSchema: {
16547
+ type: "object",
16548
+ properties: {
16549
+ filePath: { type: "string", description: "Path to the binary file" },
16550
+ patchId: { type: "string", description: "ID of the patch to remove from registry" }
16551
+ },
16552
+ required: ["filePath", "patchId"]
16553
+ }
15442
16554
  }
15443
16555
  ];
15444
16556
  server.setRequestHandler(ListToolsRequestSchema, async () => {
@@ -15516,6 +16628,32 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
15516
16628
  return await handleHexEditor(args);
15517
16629
  case "bin_convert":
15518
16630
  return await handleConvertNumber(args);
16631
+ case "bin_codesign_info":
16632
+ return await handleCodesignInfo(args);
16633
+ case "bin_codesign_remove":
16634
+ return await handleCodesignRemove(args);
16635
+ case "bin_codesign_sign":
16636
+ return await handleCodesignSign(args);
16637
+ case "bin_quarantine_check":
16638
+ return await handleQuarantineCheck(args);
16639
+ case "bin_quarantine_remove":
16640
+ return await handleQuarantineRemove(args);
16641
+ case "bin_safe_patch":
16642
+ return await handleSafePatch(args);
16643
+ case "bin_verify":
16644
+ return await handleBinVerify(args);
16645
+ case "bin_patch_register":
16646
+ return await handlePatchRegister(args);
16647
+ case "bin_patch_apply":
16648
+ return await handlePatchApply(args);
16649
+ case "bin_patch_verify":
16650
+ return await handlePatchVerify(args);
16651
+ case "bin_patch_restore":
16652
+ return await handlePatchRestore(args);
16653
+ case "bin_patch_list":
16654
+ return await handlePatchList(args);
16655
+ case "bin_patch_remove":
16656
+ return await handlePatchRemove(args);
15519
16657
  default:
15520
16658
  throw new Error(`Unknown tool: ${name}`);
15521
16659
  }