mobbdev 1.0.188 → 1.0.189

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.
Files changed (2) hide show
  1. package/dist/index.mjs +289 -57
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -32,7 +32,7 @@ var init_env = __esm({
32
32
  });
33
33
 
34
34
  // src/mcp/core/configs.ts
35
- var MCP_DEFAULT_API_URL, MCP_API_KEY_HEADER_NAME, MCP_LOGIN_MAX_WAIT, MCP_LOGIN_CHECK_DELAY, MCP_VUL_REPORT_DIGEST_TIMEOUT_MS, MCP_MAX_FILE_SIZE, MCP_PERIODIC_CHECK_INTERVAL, MCP_DEFAULT_MAX_FILES_TO_SCAN, MCP_REPORT_ID_EXPIRATION_MS, MCP_TOOLS_BROWSER_COOLDOWN_MS, MCP_DEFAULT_LIMIT, isAutoScan, MVS_AUTO_FIX_OVERRIDE, MCP_AUTO_FIX_DEBUG_MODE, MCP_PERIODIC_TRACK_INTERVAL, MCP_DEFAULT_REST_API_URL;
35
+ var MCP_DEFAULT_API_URL, MCP_API_KEY_HEADER_NAME, MCP_LOGIN_MAX_WAIT, MCP_LOGIN_CHECK_DELAY, MCP_VUL_REPORT_DIGEST_TIMEOUT_MS, MCP_MAX_FILE_SIZE, MCP_PERIODIC_CHECK_INTERVAL, MCP_DEFAULT_MAX_FILES_TO_SCAN, MCP_REPORT_ID_EXPIRATION_MS, MCP_TOOLS_BROWSER_COOLDOWN_MS, MCP_DEFAULT_LIMIT, isAutoScan, MVS_AUTO_FIX_OVERRIDE, MCP_AUTO_FIX_DEBUG_MODE, MCP_PERIODIC_TRACK_INTERVAL, MCP_DEFAULT_REST_API_URL, MCP_SYSTEM_FIND_TIMEOUT_MS;
36
36
  var init_configs = __esm({
37
37
  "src/mcp/core/configs.ts"() {
38
38
  "use strict";
@@ -53,6 +53,7 @@ var init_configs = __esm({
53
53
  MCP_AUTO_FIX_DEBUG_MODE = true;
54
54
  MCP_PERIODIC_TRACK_INTERVAL = 60 * 60 * 1e3;
55
55
  MCP_DEFAULT_REST_API_URL = "https://api.mobb.ai/api/rest/mcp/track";
56
+ MCP_SYSTEM_FIND_TIMEOUT_MS = 15 * 60 * 1e3;
56
57
  }
57
58
  });
58
59
 
@@ -11132,8 +11133,8 @@ import path8 from "path";
11132
11133
  var debug15 = Debug15("mobbdev:checkmarx");
11133
11134
  var require2 = createRequire(import.meta.url);
11134
11135
  var getCheckmarxPath = () => {
11135
- const os5 = type();
11136
- const cxFileName = os5 === "Windows_NT" ? "cx.exe" : "cx";
11136
+ const os6 = type();
11137
+ const cxFileName = os6 === "Windows_NT" ? "cx.exe" : "cx";
11137
11138
  try {
11138
11139
  return require2.resolve(`.bin/${cxFileName}`);
11139
11140
  } catch (e) {
@@ -13223,13 +13224,15 @@ var McpGQLClient = class {
13223
13224
  async getLatestReportByRepoUrl({
13224
13225
  repoUrl,
13225
13226
  limit = MCP_DEFAULT_LIMIT,
13226
- offset = 0
13227
+ offset = 0,
13228
+ fileFilter
13227
13229
  }) {
13228
13230
  try {
13229
13231
  logDebug("[GraphQL] Calling GetLatestReportByRepoUrl query", {
13230
13232
  repoUrl,
13231
13233
  limit,
13232
- offset
13234
+ offset,
13235
+ fileFilter
13233
13236
  });
13234
13237
  let currentUserEmail = "%@%";
13235
13238
  try {
@@ -13242,11 +13245,18 @@ var McpGQLClient = class {
13242
13245
  error: err
13243
13246
  });
13244
13247
  }
13248
+ const filters = {};
13249
+ if (fileFilter && fileFilter.length > 0) {
13250
+ filters["vulnerabilityReportIssues"] = {
13251
+ codeNodes: { path: { _in: fileFilter } }
13252
+ };
13253
+ }
13245
13254
  const resp = await this.clientSdk.GetLatestReportByRepoUrl({
13246
13255
  repoUrl,
13247
13256
  limit,
13248
13257
  offset,
13249
- currentUserEmail
13258
+ currentUserEmail,
13259
+ filters
13250
13260
  });
13251
13261
  logDebug("[GraphQL] GetLatestReportByRepoUrl successful", {
13252
13262
  result: resp,
@@ -13278,7 +13288,8 @@ var McpGQLClient = class {
13278
13288
  limit = MCP_DEFAULT_LIMIT,
13279
13289
  offset = 0,
13280
13290
  issueType,
13281
- severity
13291
+ severity,
13292
+ fileFilter
13282
13293
  }) {
13283
13294
  const filters = {};
13284
13295
  if (issueType && issueType.length > 0) {
@@ -13287,6 +13298,11 @@ var McpGQLClient = class {
13287
13298
  if (severity && severity.length > 0) {
13288
13299
  filters["severityText"] = { _in: severity };
13289
13300
  }
13301
+ if (fileFilter && fileFilter.length > 0) {
13302
+ filters["vulnerabilityReportIssues"] = {
13303
+ codeNodes: { path: { _in: fileFilter } }
13304
+ };
13305
+ }
13290
13306
  try {
13291
13307
  logDebug("[GraphQL] Calling GetReportFixes query", {
13292
13308
  reportId,
@@ -13294,7 +13310,8 @@ var McpGQLClient = class {
13294
13310
  offset,
13295
13311
  filters,
13296
13312
  issueType,
13297
- severity
13313
+ severity,
13314
+ fileFilter
13298
13315
  });
13299
13316
  let currentUserEmail = "%@%";
13300
13317
  try {
@@ -13477,30 +13494,34 @@ var readConfigFile = (filePath) => {
13477
13494
  return null;
13478
13495
  }
13479
13496
  };
13497
+ var mergeConfigIntoResult = (config4, mergedConfig) => {
13498
+ if (config4?.projects) {
13499
+ const allMcpServers = {};
13500
+ for (const projectPath in config4.projects) {
13501
+ const project = config4.projects[projectPath];
13502
+ if (project?.mcpServers) {
13503
+ Object.assign(allMcpServers, project.mcpServers);
13504
+ }
13505
+ }
13506
+ mergedConfig.mcpServers = { ...mergedConfig.mcpServers, ...allMcpServers };
13507
+ }
13508
+ if (config4?.mcpServers) {
13509
+ mergedConfig.mcpServers = {
13510
+ ...mergedConfig.mcpServers,
13511
+ ...config4.mcpServers
13512
+ };
13513
+ }
13514
+ if (config4?.servers) {
13515
+ mergedConfig.servers = { ...mergedConfig.servers, ...config4.servers };
13516
+ }
13517
+ };
13480
13518
  var readMCPConfig = (hostName) => {
13481
13519
  const configPaths = getMCPConfigPaths(hostName);
13482
13520
  const mergedConfig = {};
13483
13521
  for (const configPath of configPaths) {
13484
13522
  const config4 = readConfigFile(configPath);
13485
- if (hostName === "claude" && config4?.projects) {
13486
- const allMcpServers = {};
13487
- for (const projectPath in config4.projects) {
13488
- const project = config4.projects[projectPath];
13489
- if (project?.mcpServers) {
13490
- Object.assign(allMcpServers, project.mcpServers);
13491
- }
13492
- }
13493
- mergedConfig.mcpServers = { ...mergedConfig.mcpServers, ...allMcpServers };
13494
- continue;
13495
- }
13496
- if (config4?.mcpServers) {
13497
- mergedConfig.mcpServers = {
13498
- ...mergedConfig.mcpServers,
13499
- ...config4.mcpServers
13500
- };
13501
- }
13502
- if (config4?.servers) {
13503
- mergedConfig.servers = { ...mergedConfig.servers, ...config4.servers };
13523
+ if (config4) {
13524
+ mergeConfigIntoResult(config4, mergedConfig);
13504
13525
  }
13505
13526
  }
13506
13527
  return Object.keys(mergedConfig).length > 0 ? mergedConfig : null;
@@ -13610,14 +13631,31 @@ var getProcessInfo = (pid) => {
13610
13631
  return null;
13611
13632
  }
13612
13633
  };
13613
- var getHostInfo = () => {
13634
+ var getHostInfo = (additionalMcpList) => {
13614
13635
  const runningProcesses = getRunningProcesses().toLowerCase();
13615
13636
  const results = [];
13616
13637
  const allConfigs = {};
13638
+ const ideConfigPaths = /* @__PURE__ */ new Set();
13639
+ for (const ide of IDEs) {
13640
+ const configPaths = getMCPConfigPaths(ide);
13641
+ configPaths.forEach((path17) => ideConfigPaths.add(path17));
13642
+ }
13643
+ const uniqueAdditionalPaths = additionalMcpList.filter(
13644
+ (path17) => !ideConfigPaths.has(path17)
13645
+ );
13617
13646
  for (const ide of IDEs) {
13618
13647
  const cfg = readMCPConfig(ide);
13619
13648
  if (cfg) allConfigs[ide] = cfg;
13620
13649
  }
13650
+ for (const additionalPath of uniqueAdditionalPaths) {
13651
+ const config4 = readConfigFile(additionalPath);
13652
+ if (!config4) continue;
13653
+ const mergedConfig = {};
13654
+ mergeConfigIntoResult(config4, mergedConfig);
13655
+ if (Object.keys(mergedConfig).length > 0) {
13656
+ allConfigs["system"] = mergedConfig;
13657
+ }
13658
+ }
13621
13659
  const servers = [];
13622
13660
  for (const [ide, cfg] of Object.entries(allConfigs)) {
13623
13661
  for (const [name, server] of Object.entries(
@@ -13718,8 +13756,90 @@ var getHostInfo = () => {
13718
13756
  // src/mcp/services/McpUsageService/McpUsageService.ts
13719
13757
  init_configs();
13720
13758
  import fetch5 from "node-fetch";
13721
- import os4 from "os";
13759
+ import os5 from "os";
13722
13760
  import { v4 as uuidv43, v5 as uuidv5 } from "uuid";
13761
+
13762
+ // src/mcp/services/McpUsageService/system.ts
13763
+ init_configs();
13764
+ import { spawn } from "child_process";
13765
+ import os4 from "os";
13766
+ var findSystemMCPConfigs = async () => {
13767
+ try {
13768
+ const platform = os4.platform();
13769
+ let command;
13770
+ let args;
13771
+ if (platform === "win32") {
13772
+ command = "powershell";
13773
+ args = [
13774
+ "-NoProfile",
13775
+ "-Command",
13776
+ "Get-ChildItem -Path $env:USERPROFILE -Recurse -Include *mcp*.json,*claude*.json -ErrorAction SilentlyContinue | ForEach-Object { $_.FullName }"
13777
+ ];
13778
+ } else {
13779
+ const home = os4.homedir();
13780
+ command = "find";
13781
+ args = [
13782
+ home,
13783
+ "-type",
13784
+ "f",
13785
+ "(",
13786
+ "-iname",
13787
+ "*mcp*.json",
13788
+ "-o",
13789
+ "-iname",
13790
+ "*claude*.json",
13791
+ ")"
13792
+ ];
13793
+ }
13794
+ return await new Promise((resolve) => {
13795
+ const child = spawn(command, args, {
13796
+ stdio: ["ignore", "pipe", "pipe"],
13797
+ shell: platform === "win32"
13798
+ // needed for PowerShell
13799
+ });
13800
+ let output = "";
13801
+ let errorOutput = "";
13802
+ const timer = setTimeout(() => {
13803
+ child.kill("SIGTERM");
13804
+ logWarn(
13805
+ `MCP config search timed out after ${MCP_SYSTEM_FIND_TIMEOUT_MS / 1e3}s`
13806
+ );
13807
+ resolve([]);
13808
+ }, MCP_SYSTEM_FIND_TIMEOUT_MS);
13809
+ child.stdout.on("data", (data) => {
13810
+ output += data.toString();
13811
+ });
13812
+ child.stderr.on("data", (data) => {
13813
+ const msg = data.toString();
13814
+ if (!msg.includes("Operation not permitted") && !msg.includes("Permission denied") && !msg.includes("Access is denied")) {
13815
+ errorOutput += msg;
13816
+ }
13817
+ });
13818
+ child.on("error", (err) => {
13819
+ clearTimeout(timer);
13820
+ logWarn("MCP config search failed to start", { err });
13821
+ resolve([]);
13822
+ });
13823
+ child.on("close", (code) => {
13824
+ clearTimeout(timer);
13825
+ if (code === 0 || output.trim().length > 0) {
13826
+ const files = output.split(/\r?\n/).map((f) => f.trim()).filter(Boolean);
13827
+ resolve(files);
13828
+ } else {
13829
+ if (errorOutput.trim().length > 0) {
13830
+ logWarn("MCP config search finished with warnings", { errorOutput });
13831
+ }
13832
+ resolve([]);
13833
+ }
13834
+ });
13835
+ });
13836
+ } catch (err) {
13837
+ logWarn("MCP config search unexpected error", { err });
13838
+ return [];
13839
+ }
13840
+ };
13841
+
13842
+ // src/mcp/services/McpUsageService/McpUsageService.ts
13723
13843
  var McpUsageService = class {
13724
13844
  constructor(govOrgId) {
13725
13845
  __publicField(this, "configKey", "mcpUsage");
@@ -13734,6 +13854,10 @@ var McpUsageService = class {
13734
13854
  this.REST_API_URL = `${domain}/api/rest/mcp/track`;
13735
13855
  }
13736
13856
  }
13857
+ async performSystemSearchAndTracking() {
13858
+ const additionalMcpList = await findSystemMCPConfigs();
13859
+ await this.trackServerStart(additionalMcpList);
13860
+ }
13737
13861
  startPeriodicTracking() {
13738
13862
  if (!this.hasOrganizationId()) {
13739
13863
  logDebug(
@@ -13742,17 +13866,21 @@ var McpUsageService = class {
13742
13866
  return;
13743
13867
  }
13744
13868
  logDebug(`[UsageService] Starting periodic tracking for mcps`, {});
13869
+ if (this.intervalId) {
13870
+ return;
13871
+ }
13872
+ setTimeout(() => this.performSystemSearchAndTracking(), 0);
13745
13873
  this.intervalId = setInterval(async () => {
13746
13874
  logDebug(`[UsageService] Triggering periodic usage service`, {
13747
13875
  MCP_PERIODIC_TRACK_INTERVAL
13748
13876
  });
13749
- await this.trackServerStart();
13750
- }, 1e4);
13877
+ await this.performSystemSearchAndTracking();
13878
+ }, MCP_PERIODIC_TRACK_INTERVAL);
13751
13879
  }
13752
13880
  generateHostId() {
13753
13881
  const stored = configStore.get(this.configKey);
13754
13882
  if (stored?.mcpHostId) return stored.mcpHostId;
13755
- const interfaces = os4.networkInterfaces();
13883
+ const interfaces = os5.networkInterfaces();
13756
13884
  const macs = [];
13757
13885
  for (const iface of Object.values(interfaces)) {
13758
13886
  if (!iface) continue;
@@ -13760,7 +13888,7 @@ var McpUsageService = class {
13760
13888
  if (net.mac && net.mac !== "00:00:00:00:00:00") macs.push(net.mac);
13761
13889
  }
13762
13890
  }
13763
- const macString = macs.length ? macs.sort().join(",") : `${os4.hostname()}-${uuidv43()}`;
13891
+ const macString = macs.length ? macs.sort().join(",") : `${os5.hostname()}-${uuidv43()}`;
13764
13892
  const hostId = uuidv5(macString, uuidv5.DNS);
13765
13893
  logDebug("[UsageService] Generated new host ID", { hostId });
13766
13894
  return hostId;
@@ -13777,13 +13905,13 @@ var McpUsageService = class {
13777
13905
  hasOrganizationId() {
13778
13906
  return !!this.govOrgId;
13779
13907
  }
13780
- createUsageData(mcpHostId, organizationId, status) {
13781
- const { user, mcps } = getHostInfo();
13908
+ createUsageData(mcpHostId, organizationId, status, additionalMcpList) {
13909
+ const { user, mcps } = getHostInfo(additionalMcpList);
13782
13910
  return {
13783
13911
  mcpHostId,
13784
13912
  organizationId,
13785
13913
  mcpVersion: packageJson.version,
13786
- mcpOsName: os4.platform(),
13914
+ mcpOsName: os5.platform(),
13787
13915
  mcps: JSON.stringify(mcps),
13788
13916
  status,
13789
13917
  userName: user.name,
@@ -13792,7 +13920,10 @@ var McpUsageService = class {
13792
13920
  // it's used to make sure we track the mcp usage daily
13793
13921
  };
13794
13922
  }
13795
- async trackUsage(status) {
13923
+ async trackUsage({
13924
+ status,
13925
+ additionalMcpList
13926
+ }) {
13796
13927
  try {
13797
13928
  const hostId = this.generateHostId();
13798
13929
  const organizationId = this.getOrganizationId();
@@ -13802,7 +13933,12 @@ var McpUsageService = class {
13802
13933
  );
13803
13934
  return;
13804
13935
  }
13805
- const usageData = this.createUsageData(hostId, organizationId, status);
13936
+ const usageData = this.createUsageData(
13937
+ hostId,
13938
+ organizationId,
13939
+ status,
13940
+ additionalMcpList
13941
+ );
13806
13942
  const stored = configStore.get(this.configKey);
13807
13943
  const hasChanges = !stored || Object.keys(usageData).some(
13808
13944
  (key) => usageData[key] !== stored[key]
@@ -13847,11 +13983,11 @@ var McpUsageService = class {
13847
13983
  );
13848
13984
  }
13849
13985
  }
13850
- async trackServerStart() {
13851
- await this.trackUsage("ACTIVE");
13986
+ async trackServerStart(additionalMcpList = []) {
13987
+ await this.trackUsage({ status: "ACTIVE", additionalMcpList });
13852
13988
  }
13853
13989
  async trackServerStop() {
13854
- await this.trackUsage("INACTIVE");
13990
+ await this.trackUsage({ status: "INACTIVE", additionalMcpList: [] });
13855
13991
  }
13856
13992
  reset() {
13857
13993
  if (!this.intervalId) {
@@ -14984,6 +15120,35 @@ ${autoFixSettingsSection}
14984
15120
 
14985
15121
  ${whatHappensNextSection}`;
14986
15122
  };
15123
+ var noChangedFilesFoundPrompt = `\u{1F50D} **MOBB SECURITY SCAN: NO CHANGED FILES DETECTED**
15124
+
15125
+ ## \u{1F4CB} Current Status
15126
+
15127
+ No changed files were found in the working directory for security scanning.
15128
+
15129
+ ## \u{1F914} What This Means
15130
+
15131
+ This situation occurs when:
15132
+ \u2022 **Clean Working Directory**: All files are committed and there are no uncommitted changes
15133
+ \u2022 **Fresh Repository**: The repository has been recently cloned or initialized
15134
+ \u2022 **All Changes Committed**: Recent modifications have already been committed to git
15135
+
15136
+ If you wish to scan files that were recently changed in your git history call the tool with the following parameters:
15137
+
15138
+ \`\`\`json
15139
+ {
15140
+ "path": "/path/to/your/repository",
15141
+ "maxFiles": 50,
15142
+ "rescan": true,
15143
+ "scanRecentlyChangedFiles": true
15144
+ }
15145
+ \`\`\`
15146
+
15147
+
15148
+ \u2022 **scanRecentlyChangedFiles**: Set to \`true\` to automatically scan recently modified files from git history
15149
+ \u2022 **maxFiles**: Specify the maximum number of files to scan (higher = more comprehensive) (default: ${MCP_DEFAULT_MAX_FILES_TO_SCAN})
15150
+ \u2022 **rescan**: Set to \`true\` to force a complete fresh analysis
15151
+ `;
14987
15152
 
14988
15153
  // src/mcp/services/GetLocalFiles.ts
14989
15154
  init_FileUtils();
@@ -14996,13 +15161,15 @@ var getLocalFiles = async ({
14996
15161
  maxFileSize = MCP_MAX_FILE_SIZE,
14997
15162
  maxFiles,
14998
15163
  isAllFilesScan,
14999
- scanContext
15164
+ scanContext,
15165
+ scanRecentlyChangedFiles
15000
15166
  }) => {
15001
15167
  logDebug(`[${scanContext}] Starting getLocalFiles`, {
15002
15168
  path: path17,
15003
15169
  maxFileSize,
15004
15170
  maxFiles,
15005
- isAllFilesScan
15171
+ isAllFilesScan,
15172
+ scanRecentlyChangedFiles
15006
15173
  });
15007
15174
  try {
15008
15175
  const resolvedRepoPath = await fs12.realpath(path17);
@@ -15040,10 +15207,10 @@ var getLocalFiles = async ({
15040
15207
  try {
15041
15208
  const gitResult = await gitService.getChangedFiles();
15042
15209
  files = gitResult.files;
15043
- if (files.length === 0 || maxFiles) {
15210
+ if ((files.length === 0 || maxFiles) && (scanRecentlyChangedFiles || maxFiles)) {
15044
15211
  logDebug(
15045
15212
  `[${scanContext}] No changes found or maxFiles specified, getting recently changed files`,
15046
- { maxFiles }
15213
+ { maxFiles, scanRecentlyChangedFiles }
15047
15214
  );
15048
15215
  const recentResult = await gitService.getRecentlyChangedFiles({
15049
15216
  maxFiles
@@ -17265,10 +17432,12 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
17265
17432
  `[${scanContext}] Connected to the API, assembling list of files to scan`,
17266
17433
  { path: path17 }
17267
17434
  );
17435
+ const isBackgroundScan = scanContext === ScanContext.BACKGROUND_INITIAL || scanContext === ScanContext.BACKGROUND_PERIODIC;
17268
17436
  const files = await getLocalFiles({
17269
17437
  path: path17,
17270
17438
  isAllFilesScan,
17271
- scanContext
17439
+ scanContext,
17440
+ scanRecentlyChangedFiles: !isBackgroundScan
17272
17441
  });
17273
17442
  const scanStartTime = Date.now();
17274
17443
  logDebug(
@@ -17859,19 +18028,21 @@ var _FetchAvailableFixesService = class _FetchAvailableFixesService {
17859
18028
  async checkForAvailableFixes({
17860
18029
  repoUrl,
17861
18030
  limit = MCP_DEFAULT_LIMIT,
17862
- offset
18031
+ offset,
18032
+ fileFilter
17863
18033
  }) {
17864
18034
  try {
17865
- logDebug("Checking for available fixes", { repoUrl, limit });
18035
+ logDebug("Checking for available fixes", { repoUrl, limit, fileFilter });
17866
18036
  const gqlClient = await this.initializeGqlClient();
17867
18037
  logDebug("GQL client initialized");
17868
- logDebug("querying for latest report", { repoUrl, limit });
18038
+ logDebug("querying for latest report", { repoUrl, limit, fileFilter });
17869
18039
  const effectiveOffset = offset ?? (this.currentOffset || 0);
17870
18040
  logDebug("effectiveOffset", { effectiveOffset });
17871
18041
  const { fixReport, expiredReport } = await gqlClient.getLatestReportByRepoUrl({
17872
18042
  repoUrl,
17873
18043
  limit,
17874
- offset: effectiveOffset
18044
+ offset: effectiveOffset,
18045
+ fileFilter
17875
18046
  });
17876
18047
  logDebug("received latest report result", { fixReport, expiredReport });
17877
18048
  if (!fixReport) {
@@ -17926,11 +18097,20 @@ Required argument:
17926
18097
  Optional arguments:
17927
18098
  \u2022 offset \u2013 pagination offset (integer).
17928
18099
  \u2022 limit \u2013 maximum number of fixes to return (integer).
18100
+ \u2022 fileFilter \u2013 list of file paths relative to the path parameter to filter fixes by. Only fixes affecting these files will be returned. INCOMPATIBLE with fetchFixesFromAnyFile.
18101
+ \u2022 fetchFixesFromAnyFile \u2013 if true, fetches fixes for all files in the repository. If false or not set (default), filters fixes to only those affecting files with changes in git status. INCOMPATIBLE with fileFilter.
17929
18102
 
17930
18103
  The tool will:
17931
18104
  1. Validate that the provided path is secure and exists.
17932
18105
  2. Verify that the directory is a valid Git repository with an "origin" remote.
17933
- 3. Query the MOBB service by the origin remote URL and return a textual summary of available fixes (total and by severity) or a message if none are found.
18106
+ 3. Apply file filtering based on parameters (see below).
18107
+ 4. Query the MOBB service by the origin remote URL and return a textual summary of available fixes (total and by severity) or a message if none are found.
18108
+
18109
+ File Filtering Behavior:
18110
+ \u2022 If fetchFixesFromAnyFile is true: Returns fixes for all files (no filtering).
18111
+ \u2022 If fileFilter is provided: Returns only fixes affecting the specified files.
18112
+ \u2022 If neither is provided (default): Returns only fixes affecting files with changes in git status.
18113
+ \u2022 If BOTH are provided: Returns an error (parameters are mutually exclusive).
17934
18114
 
17935
18115
  Call this tool instead of ${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES} when you only need a fixes summary and do NOT want to perform scanning or code modifications.`);
17936
18116
  __publicField(this, "hasAuthentication", true);
@@ -17948,6 +18128,17 @@ Call this tool instead of ${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES} when you only
17948
18128
  limit: {
17949
18129
  type: "number",
17950
18130
  description: "[Optional] maximum number of results to return"
18131
+ },
18132
+ fileFilter: {
18133
+ type: "array",
18134
+ items: {
18135
+ type: "string"
18136
+ },
18137
+ description: "[Optional] list of file paths relative to the path parameter to filter fixes by. Only fixes affecting these files will be returned. INCOMPATIBLE with fetchFixesFromAnyFile"
18138
+ },
18139
+ fetchFixesFromAnyFile: {
18140
+ type: "boolean",
18141
+ description: "[Optional] if true, fetches fixes for all files in the repository. If false or not set, filters fixes to only those affecting files with changes in git status. INCOMPATIBLE with fileFilter"
17951
18142
  }
17952
18143
  },
17953
18144
  required: ["path"]
@@ -17957,7 +18148,13 @@ Call this tool instead of ${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES} when you only
17957
18148
  "Full local path to the cloned git repository to check for available fixes"
17958
18149
  ),
17959
18150
  offset: z35.number().optional().describe("Optional offset for pagination"),
17960
- limit: z35.number().optional().describe("Optional maximum number of fixes to return")
18151
+ limit: z35.number().optional().describe("Optional maximum number of fixes to return"),
18152
+ fileFilter: z35.array(z35.string()).optional().describe(
18153
+ "Optional list of file paths relative to the path parameter to filter fixes by. INCOMPATIBLE with fetchFixesFromAnyFile"
18154
+ ),
18155
+ fetchFixesFromAnyFile: z35.boolean().optional().describe(
18156
+ "Optional boolean to fetch fixes for all files. INCOMPATIBLE with fileFilter"
18157
+ )
17961
18158
  }));
17962
18159
  __publicField(this, "availableFixesService");
17963
18160
  this.availableFixesService = FetchAvailableFixesService.getInstance();
@@ -17984,10 +18181,37 @@ Call this tool instead of ${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES} when you only
17984
18181
  if (!originUrl) {
17985
18182
  throw new Error("No origin URL found for the repository");
17986
18183
  }
18184
+ if (args.fileFilter && args.fetchFixesFromAnyFile) {
18185
+ throw new Error(
18186
+ 'Parameters "fileFilter" and "fetchFixesFromAnyFile" are mutually exclusive. Please provide only one of these parameters:\n - Use "fileFilter" to specify a custom list of files to filter by\n - Use "fetchFixesFromAnyFile: true" to fetch fixes for all files without filtering\n - Use neither to automatically filter by files with changes in git status (default behavior)'
18187
+ );
18188
+ }
18189
+ let actualFileFilter;
18190
+ if (args.fetchFixesFromAnyFile === true) {
18191
+ actualFileFilter = void 0;
18192
+ logDebug("Fetching fixes for all files (no filtering)");
18193
+ } else if (args.fileFilter && args.fileFilter.length > 0) {
18194
+ actualFileFilter = args.fileFilter;
18195
+ logDebug("Using provided file filter", { fileFilter: actualFileFilter });
18196
+ } else {
18197
+ logDebug("Getting files from git status for filtering");
18198
+ const gitStatusResult = await gitService.getChangedFiles();
18199
+ if (gitStatusResult.files.length === 0) {
18200
+ logDebug("No changed files found in git status");
18201
+ actualFileFilter = void 0;
18202
+ } else {
18203
+ actualFileFilter = gitStatusResult.files;
18204
+ logDebug("Using files from git status as filter", {
18205
+ fileCount: actualFileFilter.length,
18206
+ files: actualFileFilter
18207
+ });
18208
+ }
18209
+ }
17987
18210
  const fixResult = await this.availableFixesService.checkForAvailableFixes({
17988
18211
  repoUrl: originUrl,
17989
18212
  limit: args.limit,
17990
- offset: args.offset
18213
+ offset: args.offset,
18214
+ fileFilter: actualFileFilter
17991
18215
  });
17992
18216
  logDebug("FetchAvailableFixesTool execution completed successfully", {
17993
18217
  fixResult
@@ -18023,7 +18247,7 @@ var _McpCheckerService = class _McpCheckerService {
18023
18247
  };
18024
18248
  }
18025
18249
  logInfo("Executing built-in mcp_checker tool");
18026
- const hostInfo = getHostInfo();
18250
+ const hostInfo = getHostInfo([]);
18027
18251
  const mcpServersInfo = hostInfo.mcps.filter((mcp) => mcp.mcpName !== "unknown").map(
18028
18252
  (mcp) => `- ${mcp.mcpName} (${mcp.ideName} ${mcp.ideVersion}): ${mcp.isRunning ? "\u2705 Running" : "\u274C Not Running"}`
18029
18253
  ).join("\n");
@@ -18280,7 +18504,10 @@ Example payload:
18280
18504
  maxFiles: z37.number().optional().describe(
18281
18505
  `Optional maximum number of files to scan (default: ${MCP_DEFAULT_MAX_FILES_TO_SCAN}). Increase for comprehensive scans of larger codebases or decrease for faster focused scans.`
18282
18506
  ),
18283
- rescan: z37.boolean().optional().describe("Optional whether to rescan the repository")
18507
+ rescan: z37.boolean().optional().describe("Optional whether to rescan the repository"),
18508
+ scanRecentlyChangedFiles: z37.boolean().optional().describe(
18509
+ "Optional whether to automatically scan recently changed files when no changed files are found in git status. If false, the tool will prompt the user instead."
18510
+ )
18284
18511
  }));
18285
18512
  __publicField(this, "inputSchema", {
18286
18513
  type: "object",
@@ -18304,6 +18531,10 @@ Example payload:
18304
18531
  rescan: {
18305
18532
  type: "boolean",
18306
18533
  description: "[Optional] whether to rescan the repository"
18534
+ },
18535
+ scanRecentlyChangedFiles: {
18536
+ type: "boolean",
18537
+ description: "[Optional] whether to automatically scan recently changed files when no changed files are found in git status. If false, the tool will prompt the user instead."
18307
18538
  }
18308
18539
  },
18309
18540
  required: ["path"]
@@ -18330,7 +18561,8 @@ Example payload:
18330
18561
  path: path17,
18331
18562
  maxFileSize: MCP_MAX_FILE_SIZE,
18332
18563
  maxFiles: args.maxFiles,
18333
- scanContext: ScanContext.USER_REQUEST
18564
+ scanContext: ScanContext.USER_REQUEST,
18565
+ scanRecentlyChangedFiles: args.scanRecentlyChangedFiles
18334
18566
  });
18335
18567
  logDebug("Files", { files });
18336
18568
  if (files.length === 0) {
@@ -18338,7 +18570,7 @@ Example payload:
18338
18570
  content: [
18339
18571
  {
18340
18572
  type: "text",
18341
- text: "No changed files found in the repository. The vulnerability scanner analyzes modified, added, or staged files. Make some changes to your code and try again."
18573
+ text: noChangedFilesFoundPrompt
18342
18574
  }
18343
18575
  ]
18344
18576
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mobbdev",
3
- "version": "1.0.188",
3
+ "version": "1.0.189",
4
4
  "description": "Automated secure code remediation tool",
5
5
  "repository": "git+https://github.com/mobb-dev/bugsy.git",
6
6
  "main": "dist/index.mjs",