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.
- package/dist/index.mjs +289 -57
- 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
|
|
11136
|
-
const cxFileName =
|
|
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 (
|
|
13486
|
-
|
|
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
|
|
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.
|
|
13750
|
-
},
|
|
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 =
|
|
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(",") : `${
|
|
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:
|
|
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(
|
|
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(
|
|
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.
|
|
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:
|
|
18573
|
+
text: noChangedFilesFoundPrompt
|
|
18342
18574
|
}
|
|
18343
18575
|
]
|
|
18344
18576
|
};
|