mobbdev 1.0.102 → 1.0.104

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 +510 -380
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -501,6 +501,7 @@ var Vulnerability_Report_Issue_Tag_Enum = /* @__PURE__ */ ((Vulnerability_Report
501
501
  Vulnerability_Report_Issue_Tag_Enum3["AutogeneratedCode"] = "AUTOGENERATED_CODE";
502
502
  Vulnerability_Report_Issue_Tag_Enum3["AuxiliaryCode"] = "AUXILIARY_CODE";
503
503
  Vulnerability_Report_Issue_Tag_Enum3["FalsePositive"] = "FALSE_POSITIVE";
504
+ Vulnerability_Report_Issue_Tag_Enum3["Suppressed"] = "SUPPRESSED";
504
505
  Vulnerability_Report_Issue_Tag_Enum3["TestCode"] = "TEST_CODE";
505
506
  Vulnerability_Report_Issue_Tag_Enum3["Unfixable"] = "UNFIXABLE";
506
507
  Vulnerability_Report_Issue_Tag_Enum3["VendorCode"] = "VENDOR_CODE";
@@ -555,6 +556,80 @@ var FixDetailsFragmentDoc = `
555
556
  }
556
557
  }
557
558
  `;
559
+ var FixReportSummaryFieldsFragmentDoc = `
560
+ fragment FixReportSummaryFields on fixReport {
561
+ id
562
+ createdOn
563
+ repo {
564
+ originalUrl
565
+ }
566
+ issueTypes
567
+ CRITICAL: fixes_aggregate(
568
+ where: {_and: [{vulnerabilityReportIssues: {category: {_eq: "Fixable"}}}, {severityText: {_eq: "critical"}}]}
569
+ ) {
570
+ aggregate {
571
+ count
572
+ }
573
+ }
574
+ HIGH: fixes_aggregate(
575
+ where: {_and: [{vulnerabilityReportIssues: {category: {_eq: "Fixable"}}}, {severityText: {_eq: "high"}}]}
576
+ ) {
577
+ aggregate {
578
+ count
579
+ }
580
+ }
581
+ MEDIUM: fixes_aggregate(
582
+ where: {_and: [{vulnerabilityReportIssues: {category: {_eq: "Fixable"}}}, {severityText: {_eq: "medium"}}]}
583
+ ) {
584
+ aggregate {
585
+ count
586
+ }
587
+ }
588
+ LOW: fixes_aggregate(
589
+ where: {_and: [{vulnerabilityReportIssues: {category: {_eq: "Fixable"}}}, {severityText: {_eq: "low"}}]}
590
+ ) {
591
+ aggregate {
592
+ count
593
+ }
594
+ }
595
+ fixes(
596
+ where: {_and: [{vulnerabilityReportIssues: {category: {_eq: "Fixable"}}}, $filters]}
597
+ order_by: {severityValue: desc}
598
+ limit: $limit
599
+ offset: $offset
600
+ ) {
601
+ ...FixDetails
602
+ }
603
+ filteredFixesCount: fixes_aggregate(
604
+ where: {_and: [{vulnerabilityReportIssues: {category: {_eq: "Fixable"}}}, $filters]}
605
+ ) {
606
+ aggregate {
607
+ count
608
+ }
609
+ }
610
+ totalFixesCount: fixes_aggregate {
611
+ aggregate {
612
+ count
613
+ }
614
+ }
615
+ vulnerabilityReport {
616
+ scanDate
617
+ vendor
618
+ totalVulnerabilityReportIssuesCount: vulnerabilityReportIssues_aggregate {
619
+ aggregate {
620
+ count
621
+ }
622
+ }
623
+ notFixableVulnerabilityReportIssuesCount: vulnerabilityReportIssues_aggregate(
624
+ where: {category: {_neq: "Fixable"}}
625
+ ) {
626
+ aggregate {
627
+ count
628
+ }
629
+ }
630
+ }
631
+ }
632
+ ${FixDetailsFragmentDoc}`;
558
633
  var MeDocument = `
559
634
  query Me {
560
635
  me {
@@ -984,80 +1059,24 @@ var AutoPrAnalysisDocument = `
984
1059
  }
985
1060
  }
986
1061
  `;
987
- var GetMcpFixesDocument = `
988
- query GetMCPFixes($fixReportId: uuid!) {
989
- fix(where: {fixReportId: {_eq: $fixReportId}}) {
990
- ...FixDetails
991
- }
992
- }
993
- ${FixDetailsFragmentDoc}`;
994
1062
  var GetLatestReportByRepoUrlDocument = `
995
- query GetLatestReportByRepoUrl($repoUrl: String!, $limit: Int = 3) {
1063
+ query GetLatestReportByRepoUrl($repoUrl: String!, $filters: fix_bool_exp = {}, $limit: Int!, $offset: Int!) {
996
1064
  fixReport(
997
1065
  where: {repo: {originalUrl: {_eq: $repoUrl}}}
998
1066
  order_by: {createdOn: desc}
999
1067
  limit: 1
1000
1068
  ) {
1001
- id
1002
- createdOn
1003
- repo {
1004
- originalUrl
1005
- }
1006
- issueTypes
1007
- fixes_aggregate(
1008
- where: {vulnerabilityReportIssues: {category: {_eq: "Fixable"}}}
1009
- ) {
1010
- aggregate {
1011
- count
1012
- }
1013
- }
1014
- CRITICAL: fixes_aggregate(
1015
- where: {_and: [{vulnerabilityReportIssues: {category: {_eq: "Fixable"}}}, {severityText: {_eq: "critical"}}]}
1016
- ) {
1017
- aggregate {
1018
- count
1019
- }
1020
- }
1021
- HIGH: fixes_aggregate(
1022
- where: {_and: [{vulnerabilityReportIssues: {category: {_eq: "Fixable"}}}, {severityText: {_eq: "high"}}]}
1023
- ) {
1024
- aggregate {
1025
- count
1026
- }
1027
- }
1028
- MEDIUM: fixes_aggregate(
1029
- where: {_and: [{vulnerabilityReportIssues: {category: {_eq: "Fixable"}}}, {severityText: {_eq: "medium"}}]}
1030
- ) {
1031
- aggregate {
1032
- count
1033
- }
1034
- }
1035
- LOW: fixes_aggregate(
1036
- where: {_and: [{vulnerabilityReportIssues: {category: {_eq: "Fixable"}}}, {severityText: {_eq: "low"}}]}
1037
- ) {
1038
- aggregate {
1039
- count
1040
- }
1041
- }
1042
- fixes(
1043
- where: {vulnerabilityReportIssues: {category: {_eq: "Fixable"}}}
1044
- order_by: {severityValue: desc}
1045
- limit: $limit
1046
- ) {
1047
- ...FixDetails
1048
- }
1049
- vulnerabilityReport {
1050
- scanDate
1051
- vendor
1052
- vulnerabilityReportIssues_aggregate(where: {category: {_eq: "Fixable"}}) {
1053
- aggregate {
1054
- count
1055
- }
1056
- }
1057
- }
1069
+ ...FixReportSummaryFields
1058
1070
  }
1059
1071
  }
1060
- ${FixDetailsFragmentDoc}`;
1072
+ ${FixReportSummaryFieldsFragmentDoc}`;
1073
+ var GetReportFixesDocument = `
1074
+ query GetReportFixes($reportId: uuid!, $filters: fix_bool_exp = {}, $limit: Int!, $offset: Int!) {
1075
+ fixReport(where: {id: {_eq: $reportId}}) {
1076
+ ...FixReportSummaryFields
1077
+ }
1078
+ }
1079
+ ${FixReportSummaryFieldsFragmentDoc}`;
1061
1080
  var defaultWrapper = (action, _operationName, _operationType, _variables) => action();
1062
1081
  function getSdk(client, withWrapper = defaultWrapper) {
1063
1082
  return {
@@ -1124,11 +1143,11 @@ function getSdk(client, withWrapper = defaultWrapper) {
1124
1143
  autoPrAnalysis(variables, requestHeaders, signal) {
1125
1144
  return withWrapper((wrappedRequestHeaders) => client.request({ document: AutoPrAnalysisDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "autoPrAnalysis", "mutation", variables);
1126
1145
  },
1127
- GetMCPFixes(variables, requestHeaders, signal) {
1128
- return withWrapper((wrappedRequestHeaders) => client.request({ document: GetMcpFixesDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "GetMCPFixes", "query", variables);
1129
- },
1130
1146
  GetLatestReportByRepoUrl(variables, requestHeaders, signal) {
1131
1147
  return withWrapper((wrappedRequestHeaders) => client.request({ document: GetLatestReportByRepoUrlDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "GetLatestReportByRepoUrl", "query", variables);
1148
+ },
1149
+ GetReportFixes(variables, requestHeaders, signal) {
1150
+ return withWrapper((wrappedRequestHeaders) => client.request({ document: GetReportFixesDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "GetReportFixes", "query", variables);
1132
1151
  }
1133
1152
  };
1134
1153
  }
@@ -1534,6 +1553,8 @@ function getTagTooltip(tag) {
1534
1553
  return "Issue found in supporting files that don't impact core functionality";
1535
1554
  case "Filtered":
1536
1555
  return "Issue was filtered by user in the Fix Policy";
1556
+ case "SUPPRESSED":
1557
+ return "Suppressed in the scan report";
1537
1558
  default:
1538
1559
  return tag;
1539
1560
  }
@@ -1544,7 +1565,8 @@ var issueDescription = {
1544
1565
  ["FALSE_POSITIVE" /* FalsePositive */]: "The flagged code **does not represent an actual vulnerability within the application's context.** This categorization indicates that the issue is either misidentified by the scanner or deemed irrelevant to the application's functionality.",
1545
1566
  ["TEST_CODE" /* TestCode */]: "The flagged code resides in a test-specific path or context. This categorization indicates that **it supports testing scenarios and is isolated from production use**.",
1546
1567
  ["UNFIXABLE" /* Unfixable */]: "The flagged code cannot be fixed",
1547
- ["VENDOR_CODE" /* VendorCode */]: "The flagged code originates from a third-party library or dependency maintained externally. This categorization suggests that **the issue lies outside the application's direct control** and should be addressed by the vendor if necessary."
1568
+ ["VENDOR_CODE" /* VendorCode */]: "The flagged code originates from a third-party library or dependency maintained externally. This categorization suggests that **the issue lies outside the application's direct control** and should be addressed by the vendor if necessary.",
1569
+ ["SUPPRESSED" /* Suppressed */]: "Suppressed in the scan report."
1548
1570
  };
1549
1571
  function replaceKeysWithValues(fixDescription, extraContext) {
1550
1572
  let result = fixDescription;
@@ -3925,7 +3947,7 @@ var GetProjectMembersDataZ = z11.object({
3925
3947
  }),
3926
3948
  user: z11.object({
3927
3949
  id: z11.string().uuid(),
3928
- picture: z11.string().optional(),
3950
+ picture: z11.string().nullable().optional(),
3929
3951
  name: z11.string().nullish(),
3930
3952
  email: z11.string().email()
3931
3953
  })
@@ -10987,7 +11009,7 @@ async function handleMobbLogin({
10987
11009
  const newGqlClient = new GQLClient({ apiKey: newApiToken, type: "apiKey" });
10988
11010
  const loginSuccess = await newGqlClient.verifyToken();
10989
11011
  if (loginSuccess) {
10990
- debug18("set api token %s", newApiToken);
11012
+ debug18(`set api token ${newApiToken}`);
10991
11013
  config3.set("apiToken", newApiToken);
10992
11014
  loginSpinner.success({
10993
11015
  text: `\u{1F513} Login to Mobb successful! ${typeof loginSpinner === "string" ? `Logged in as ${loginSuccess}` : ""}`
@@ -11146,24 +11168,96 @@ import {
11146
11168
  // src/mcp/Logger.ts
11147
11169
  var logglerUrl = "http://localhost:4444/log";
11148
11170
  var isTestEnvironment = process.env["VITEST"] || process.env["TEST"];
11171
+ var CIRCUIT_BREAKER_TIME = 5e3;
11172
+ var URL_CHECK_TIMEOUT = 200;
11173
+ var MAX_QUEUE_SIZE = 100;
11149
11174
  var Logger = class {
11175
+ constructor() {
11176
+ __publicField(this, "queue", []);
11177
+ __publicField(this, "isProcessing", false);
11178
+ __publicField(this, "isCircuitBroken", false);
11179
+ __publicField(this, "circuitBreakerTimer", null);
11180
+ }
11150
11181
  log(message, level = "info", data) {
11182
+ if (isTestEnvironment) return;
11183
+ if (this.queue.length >= MAX_QUEUE_SIZE) {
11184
+ this.queue.shift();
11185
+ }
11186
+ this.queue.push({ message, level, data });
11187
+ if (!this.isProcessing && !this.isCircuitBroken) {
11188
+ this.processQueue();
11189
+ }
11190
+ }
11191
+ async isUrlReachable(url) {
11192
+ try {
11193
+ const controller = new AbortController();
11194
+ const timeoutId = setTimeout(() => controller.abort(), URL_CHECK_TIMEOUT);
11195
+ await fetch(url, {
11196
+ method: "HEAD",
11197
+ signal: controller.signal
11198
+ });
11199
+ clearTimeout(timeoutId);
11200
+ return true;
11201
+ } catch (error) {
11202
+ return false;
11203
+ }
11204
+ }
11205
+ async processQueue() {
11206
+ if (this.queue.length === 0 || this.isCircuitBroken) {
11207
+ this.isProcessing = false;
11208
+ return;
11209
+ }
11210
+ this.isProcessing = true;
11211
+ const logEntry = this.queue[0];
11212
+ if (!logEntry) {
11213
+ this.isProcessing = false;
11214
+ return;
11215
+ }
11216
+ const isReachable = await this.isUrlReachable(logglerUrl);
11217
+ if (!isReachable) {
11218
+ this.triggerCircuitBreaker();
11219
+ return;
11220
+ }
11151
11221
  const logMessage = {
11152
11222
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
11153
- level,
11154
- message,
11155
- data
11223
+ level: logEntry.level,
11224
+ message: logEntry.message,
11225
+ data: logEntry.data
11156
11226
  };
11157
- if (!isTestEnvironment) {
11158
- try {
11159
- fetch(logglerUrl, {
11160
- method: "POST",
11161
- headers: { "Content-Type": "application/json" },
11162
- body: JSON.stringify(logMessage)
11163
- });
11164
- } catch (error) {
11227
+ const controller = new AbortController();
11228
+ const timeoutId = setTimeout(() => {
11229
+ controller.abort();
11230
+ }, 500);
11231
+ fetch(logglerUrl, {
11232
+ method: "POST",
11233
+ headers: { "Content-Type": "application/json" },
11234
+ body: JSON.stringify(logMessage),
11235
+ redirect: "error",
11236
+ // do not follow redirects
11237
+ signal: controller.signal
11238
+ }).then((_response) => {
11239
+ this.queue.shift();
11240
+ setTimeout(() => this.processQueue(), 0);
11241
+ }).catch(() => {
11242
+ this.triggerCircuitBreaker();
11243
+ }).finally(() => {
11244
+ clearTimeout(timeoutId);
11245
+ });
11246
+ }
11247
+ triggerCircuitBreaker() {
11248
+ this.isCircuitBroken = true;
11249
+ this.queue = [];
11250
+ this.isProcessing = false;
11251
+ if (this.circuitBreakerTimer) {
11252
+ clearTimeout(this.circuitBreakerTimer);
11253
+ }
11254
+ this.circuitBreakerTimer = setTimeout(() => {
11255
+ this.isCircuitBroken = false;
11256
+ this.circuitBreakerTimer = null;
11257
+ if (this.queue.length > 0 && !this.isProcessing) {
11258
+ this.processQueue();
11165
11259
  }
11166
- }
11260
+ }, CIRCUIT_BREAKER_TIME);
11167
11261
  }
11168
11262
  };
11169
11263
  var logger = new Logger();
@@ -11171,7 +11265,7 @@ var logInfo = (message, data) => logger.log(message, "info", data);
11171
11265
  var logError = (message, data) => logger.log(message, "error", data);
11172
11266
  var logWarn = (message, data) => logger.log(message, "warn", data);
11173
11267
  var logDebug = (message, data) => logger.log(message, "debug", data);
11174
- var log = logger.log;
11268
+ var log = logger.log.bind(logger);
11175
11269
 
11176
11270
  // src/mcp/services/McpGQLClient.ts
11177
11271
  import crypto2 from "crypto";
@@ -11447,24 +11541,6 @@ var McpGQLClient = class {
11447
11541
  throw e;
11448
11542
  }
11449
11543
  }
11450
- async getReportFixes(fixReportId) {
11451
- try {
11452
- logDebug("GraphQL: Calling GetMCPFixes query", { fixReportId });
11453
- const res = await this.clientSdk.GetMCPFixes({ fixReportId });
11454
- logInfo("GraphQL: GetMCPFixes successful", {
11455
- result: res,
11456
- fixCount: res.fix?.length || 0
11457
- });
11458
- return res.fix;
11459
- } catch (e) {
11460
- logError("GraphQL: GetMCPFixes failed", {
11461
- error: e,
11462
- fixReportId,
11463
- ...this.getErrorContext()
11464
- });
11465
- throw e;
11466
- }
11467
- }
11468
11544
  async getUserInfo() {
11469
11545
  const { me } = await this.clientSdk.Me();
11470
11546
  return me;
@@ -11510,15 +11586,21 @@ var McpGQLClient = class {
11510
11586
  return null;
11511
11587
  }
11512
11588
  }
11513
- async getLatestReportByRepoUrl(repoUrl, limit) {
11589
+ async getLatestReportByRepoUrl({
11590
+ repoUrl,
11591
+ limit = 3,
11592
+ offset = 0
11593
+ }) {
11514
11594
  try {
11515
11595
  logDebug("GraphQL: Calling GetLatestReportByRepoUrl query", {
11516
11596
  repoUrl,
11517
- limit
11597
+ limit,
11598
+ offset
11518
11599
  });
11519
11600
  const res = await this.clientSdk.GetLatestReportByRepoUrl({
11520
11601
  repoUrl,
11521
- limit
11602
+ limit,
11603
+ offset
11522
11604
  });
11523
11605
  logInfo("GraphQL: GetLatestReportByRepoUrl successful", {
11524
11606
  result: res,
@@ -11534,6 +11616,56 @@ var McpGQLClient = class {
11534
11616
  throw e;
11535
11617
  }
11536
11618
  }
11619
+ async getReportFixesPaginated({
11620
+ reportId,
11621
+ limit = 3,
11622
+ offset = 0,
11623
+ issueType,
11624
+ severity
11625
+ }) {
11626
+ try {
11627
+ const filters = {};
11628
+ if (issueType && issueType.length > 0) {
11629
+ filters["safeIssueType"] = { _in: issueType };
11630
+ }
11631
+ if (severity && severity.length > 0) {
11632
+ filters["severityText"] = { _in: severity };
11633
+ }
11634
+ logDebug("GraphQL: Calling GetReportFixes query", {
11635
+ reportId,
11636
+ limit,
11637
+ offset,
11638
+ filters,
11639
+ issueType,
11640
+ severity
11641
+ });
11642
+ const res = await this.clientSdk.GetReportFixes({
11643
+ reportId,
11644
+ limit,
11645
+ offset,
11646
+ filters
11647
+ });
11648
+ logInfo("GraphQL: GetReportFixes successful", {
11649
+ result: res,
11650
+ fixCount: res.fixReport?.[0]?.fixes?.length || 0,
11651
+ totalCount: res.fixReport?.[0]?.filteredFixesCount?.aggregate?.count || 0
11652
+ });
11653
+ if (res.fixReport.length === 0) {
11654
+ return null;
11655
+ }
11656
+ return {
11657
+ fixes: res.fixReport?.[0]?.fixes || [],
11658
+ totalCount: res.fixReport?.[0]?.filteredFixesCount?.aggregate?.count || 0
11659
+ };
11660
+ } catch (e) {
11661
+ logError("GraphQL: GetReportFixes failed", {
11662
+ error: e,
11663
+ reportId,
11664
+ ...this.getErrorContext()
11665
+ });
11666
+ throw e;
11667
+ }
11668
+ }
11537
11669
  };
11538
11670
  async function openBrowser(url) {
11539
11671
  const now = Date.now();
@@ -11553,7 +11685,7 @@ async function getMcpGQLClient() {
11553
11685
  });
11554
11686
  const isConnected = await inGqlClient.verifyConnection();
11555
11687
  if (!isConnected) {
11556
- throw new ApiConnectionError("Error: failed to connect to the API");
11688
+ throw new ApiConnectionError("Error: failed to connect to Mobb API");
11557
11689
  }
11558
11690
  const userVerify = await inGqlClient.verifyToken();
11559
11691
  if (userVerify) {
@@ -11596,10 +11728,10 @@ async function getMcpGQLClient() {
11596
11728
  const newGqlClient = new McpGQLClient({ apiKey: newApiToken, type: "apiKey" });
11597
11729
  const loginSuccess = await newGqlClient.verifyToken();
11598
11730
  if (loginSuccess) {
11599
- logDebug("set api token %s", newApiToken);
11731
+ logDebug(`set api token ${newApiToken}`);
11600
11732
  config4.set("apiToken", newApiToken);
11601
11733
  } else {
11602
- throw new AuthenticationError("Something went wrong, API token is invalid.");
11734
+ throw new AuthenticationError("Invalid API token");
11603
11735
  }
11604
11736
  return newGqlClient;
11605
11737
  }
@@ -11618,14 +11750,14 @@ var ToolRegistry = class {
11618
11750
  this.tools.set(tool.name, tool);
11619
11751
  logDebug(`Tool registered: ${tool.name}`, {
11620
11752
  toolName: tool.name,
11621
- description: tool.definition.description
11753
+ description: tool.description
11622
11754
  });
11623
11755
  }
11624
11756
  getTool(name) {
11625
11757
  return this.tools.get(name);
11626
11758
  }
11627
11759
  getAllTools() {
11628
- return Array.from(this.tools.values()).map((tool) => tool.definition);
11760
+ return Array.from(this.tools.values()).map((tool) => tool.getDefinition());
11629
11761
  }
11630
11762
  getToolNames() {
11631
11763
  return Array.from(this.tools.keys());
@@ -11706,10 +11838,19 @@ var McpServer = class {
11706
11838
  }
11707
11839
  async handleListToolsRequest(request) {
11708
11840
  logInfo("Received list_tools request", { params: request.params });
11841
+ logInfo("Environment", {
11842
+ env: process.env
11843
+ });
11844
+ logInfo("Request", {
11845
+ request: JSON.parse(JSON.stringify(request))
11846
+ });
11847
+ logInfo("Server", {
11848
+ server: this.server
11849
+ });
11709
11850
  void getMcpGQLClient();
11710
- const tools = this.toolRegistry.getAllTools();
11851
+ const toolsDefinitions = this.toolRegistry.getAllTools();
11711
11852
  const response = {
11712
- tools: tools.map((tool) => ({
11853
+ tools: toolsDefinitions.map((tool) => ({
11713
11854
  name: tool.name,
11714
11855
  display_name: tool.display_name || tool.name,
11715
11856
  description: tool.description || "",
@@ -11726,6 +11867,15 @@ var McpServer = class {
11726
11867
  async handleCallToolRequest(request) {
11727
11868
  const { name, arguments: args } = request.params;
11728
11869
  logInfo(`Received call tool request for ${name}`, { name, args });
11870
+ logInfo("Environment", {
11871
+ env: process.env
11872
+ });
11873
+ logInfo("Request", {
11874
+ request: JSON.parse(JSON.stringify(request))
11875
+ });
11876
+ logInfo("Server", {
11877
+ server: this.server
11878
+ });
11729
11879
  try {
11730
11880
  const tool = this.toolRegistry.getTool(name);
11731
11881
  if (!tool) {
@@ -11766,11 +11916,7 @@ var McpServer = class {
11766
11916
  logDebug("MCP server handlers registered");
11767
11917
  }
11768
11918
  registerTool(tool) {
11769
- this.toolRegistry.registerTool({
11770
- name: tool.name,
11771
- definition: tool.definition,
11772
- execute: tool.execute
11773
- });
11919
+ this.toolRegistry.registerTool(tool);
11774
11920
  logDebug(`Tool registered: ${tool.name}`);
11775
11921
  }
11776
11922
  async start() {
@@ -11848,41 +11994,26 @@ var BaseTool = class {
11848
11994
  name: this.name,
11849
11995
  display_name: this.displayName,
11850
11996
  description: this.description,
11851
- inputSchema: {
11852
- type: "object",
11853
- properties: {
11854
- path: {
11855
- type: "string",
11856
- description: "The path to the local git repository"
11857
- }
11858
- },
11859
- required: ["path"]
11860
- }
11997
+ inputSchema: this.inputSchema
11861
11998
  };
11862
11999
  }
11863
12000
  async execute(args) {
11864
12001
  logInfo(`Executing tool: ${this.name}`, { args });
12002
+ logInfo(`Authenticating tool: ${this.name}`, { args });
12003
+ const mcpGqlClient = await getMcpGQLClient();
12004
+ const userInfo = await mcpGqlClient.getUserInfo();
12005
+ logDebug("Authenticated", { userInfo });
11865
12006
  const validatedArgs = this.validateInput(args);
11866
12007
  logDebug(`Tool ${this.name} input validation successful`, {
11867
12008
  validatedArgs
11868
12009
  });
11869
- await this.validateAdditional(validatedArgs);
11870
- try {
11871
- const result = await this.executeInternal(validatedArgs);
11872
- logInfo(`Tool ${this.name} executed successfully`);
11873
- return result;
11874
- } catch (error) {
11875
- const errorMessage = error instanceof Error ? error.message : String(error);
11876
- logError(`Tool ${this.name} execution failed: ${errorMessage}`, {
11877
- error,
11878
- args
11879
- });
11880
- return this.createErrorResponse(errorMessage);
11881
- }
12010
+ const result = await this.executeInternal(validatedArgs);
12011
+ logInfo(`Tool ${this.name} executed successfully`);
12012
+ return result;
11882
12013
  }
11883
12014
  validateInput(args) {
11884
12015
  try {
11885
- return this.inputSchema.parse(args);
12016
+ return this.inputValidationSchema.parse(args);
11886
12017
  } catch (error) {
11887
12018
  if (error instanceof z31.ZodError) {
11888
12019
  const errorDetails = error.errors.map((e) => {
@@ -11896,12 +12027,6 @@ var BaseTool = class {
11896
12027
  throw error;
11897
12028
  }
11898
12029
  }
11899
- /**
11900
- * Additional validation that should bubble up as MCP errors
11901
- * Override this method in subclasses to add custom validation
11902
- */
11903
- async validateAdditional(_validatedArgs) {
11904
- }
11905
12030
  createSuccessResponse(text) {
11906
12031
  return {
11907
12032
  content: [
@@ -11912,25 +12037,27 @@ var BaseTool = class {
11912
12037
  ]
11913
12038
  };
11914
12039
  }
11915
- createErrorResponse(error) {
11916
- return {
11917
- content: [
11918
- {
11919
- type: "text",
11920
- text: error
11921
- }
11922
- ]
11923
- };
11924
- }
11925
12040
  };
11926
12041
 
11927
- // src/mcp/tools/base/prompts.ts
12042
+ // src/mcp/core/prompts.ts
11928
12043
  function frienlyType(s) {
11929
12044
  const withoutUnderscores = s.replace(/_/g, " ");
11930
12045
  const result = withoutUnderscores.replace(/([a-z])([A-Z])/g, "$1 $2");
11931
12046
  return result.charAt(0).toUpperCase() + result.slice(1);
11932
12047
  }
11933
- var applyFixesPrompt = (fixes) => {
12048
+ var noFixesReturnedForParameters = `No fixes returned for the given offset and limit parameters.
12049
+ `;
12050
+ var applyFixesPrompt = ({
12051
+ fixes,
12052
+ hasMore,
12053
+ totalCount,
12054
+ nextOffset,
12055
+ shownCount,
12056
+ currentTool
12057
+ }) => {
12058
+ if (fixes.length === 0) {
12059
+ return noFixesReturnedForParameters;
12060
+ }
11934
12061
  const fixList = fixes.map((fix) => {
11935
12062
  const vulnerabilityType = frienlyType(fix.safeIssueType);
11936
12063
  const vulnerabilityDescription = fix.patchAndQuestions?.__typename === "FixData" ? fix.patchAndQuestions.extraContext?.fixDescription : void 0;
@@ -12007,10 +12134,22 @@ ${fix.patch || "No patch available"}
12007
12134
  - Do NOT ask for permission
12008
12135
  - Explain what you did AFTER applying the patches
12009
12136
  - If any patch fails, continue with the others and report issues at the end
12137
+
12138
+ ${hasMore ? `---
12139
+
12140
+ ## More Fixes Available (${totalCount - nextOffset} remaining)
12141
+
12142
+ You have viewed ${shownCount} out of ${totalCount} available fixes.
12143
+
12144
+ To fetch additional fixes, run the \`${currentTool}\` tool again with the following parameters:
12145
+
12146
+ - **offset**: ${nextOffset} _(start index for the next batch)_
12147
+ - **limit**: <number_of_fixes_to_return> _(optional \u2013 default is 3)_
12148
+
12149
+ If you omit both **offset** and **limit**, the command will automatically return the next 3 fixes.
12150
+ ` : ""}
12010
12151
  `;
12011
12152
  };
12012
-
12013
- // src/mcp/tools/checkForAvailableFixes/helpers/AvailableFixesResponsePrompts.ts
12014
12153
  var noReportFoundPrompt = `\u{1F50D} **MOBB SECURITY SCAN STATUS**
12015
12154
 
12016
12155
  ## No Vulnerability Report Found
@@ -12036,34 +12175,19 @@ We were unable to find a previous vulnerability report for this repository. This
12036
12175
  - Confirm the repository URL matches your remote origin
12037
12176
  - Verify the URL format is correct (e.g., https://github.com/org/repo)
12038
12177
 
12039
- ### \u{1F680} Next Steps
12040
- To get started with security scanning:
12041
- 1. Run \`fix_vulnerabilities\` to perform a new scan
12042
- 2. Review the results and apply any suggested fixes
12043
- 3. Set up regular scanning to maintain security
12044
-
12045
- ### \u{1F4A1} Additional Information
12046
- - New scans typically take a few minutes to complete
12047
- - You'll receive detailed results including:
12048
- - Vulnerability types and severities
12049
- - Specific code locations
12050
- - Recommended fixes
12051
- - Security best practices
12052
-
12053
12178
  For assistance, please:
12054
12179
  - Visit our documentation at https://docs.mobb.ai
12055
12180
  - Contact support at support@mobb.ai`;
12056
- var noFixesFoundPrompt = `\u{1F50D} **MOBB SECURITY SCAN STATUS**
12057
-
12058
- ## No Available Fixes Found
12059
-
12060
- We've analyzed your repository but found no automated fixes available at this time.
12181
+ var noFixesAvailablePrompt = `There are no fixes available for this repository at this time.
12061
12182
  `;
12062
- var fixesFoundPrompt = (fixReport) => {
12063
- if (fixReport.fixes_aggregate.aggregate?.count === 0) {
12064
- return noFixesFoundPrompt;
12183
+ var fixesFoundPrompt = ({
12184
+ fixReport,
12185
+ offset
12186
+ }) => {
12187
+ const totalFixes = fixReport.filteredFixesCount.aggregate?.count || 0;
12188
+ if (totalFixes === 0) {
12189
+ return noFixesAvailablePrompt;
12065
12190
  }
12066
- const totalFixes = fixReport.fixes_aggregate.aggregate?.count || 0;
12067
12191
  const criticalFixes = fixReport.CRITICAL?.aggregate?.count || 0;
12068
12192
  const highFixes = fixReport.HIGH?.aggregate?.count || 0;
12069
12193
  const mediumFixes = fixReport.MEDIUM?.aggregate?.count || 0;
@@ -12073,6 +12197,9 @@ var fixesFoundPrompt = (fixReport) => {
12073
12197
  ).toLocaleString();
12074
12198
  const vendor = fixReport.vulnerabilityReport?.vendor || "Unknown";
12075
12199
  const reportUrl = "";
12200
+ const shownCount = fixReport.fixes.length;
12201
+ const nextOffset = offset + shownCount;
12202
+ const hasMore = nextOffset < totalFixes;
12076
12203
  return `\u{1F50D} **MOBB SECURITY SCAN RESULTS**
12077
12204
 
12078
12205
  ## \u{1F4CA} Scan Report Summary
@@ -12090,15 +12217,61 @@ Total number of fixes available: **${totalFixes}**
12090
12217
  - \u{1F534} Critical: ${criticalFixes}
12091
12218
  - \u{1F7E0} High: ${highFixes}
12092
12219
  - \u{1F7E1} Medium: ${mediumFixes}
12093
- - \uFFFD\uFFFD Low: ${lowFixes}
12220
+ - \u{1F7E2} Low: ${lowFixes}
12221
+
12222
+ ${applyFixesPrompt({
12223
+ fixes: fixReport.fixes,
12224
+ totalCount: totalFixes,
12225
+ hasMore,
12226
+ nextOffset: 0,
12227
+ shownCount: fixReport.fixes.length,
12228
+ currentTool: "check_for_available_fixes"
12229
+ })}`;
12230
+ };
12231
+ var noFixesFoundPrompt = `\u{1F50D} **MOBB SECURITY SCAN COMPLETED**
12232
+
12233
+ Mobb security scan completed successfully but found no automated fixes available at this time.
12234
+ `;
12235
+ var fixesPrompt = ({
12236
+ fixes,
12237
+ totalCount,
12238
+ offset
12239
+ }) => {
12240
+ if (totalCount === 0) {
12241
+ return noFixesFoundPrompt;
12242
+ }
12243
+ const shownCount = fixes.length;
12244
+ const nextOffset = offset + shownCount;
12245
+ const hasMore = nextOffset < totalCount;
12246
+ return `Here are the fixes to the vulnerabilities discovered by Mobb MCP
12247
+
12248
+ ${applyFixesPrompt({
12249
+ fixes,
12250
+ totalCount,
12251
+ hasMore,
12252
+ nextOffset,
12253
+ shownCount,
12254
+ currentTool: "fix_vulnerabilities"
12255
+ })}
12256
+
12257
+ ### \u{1F504} Running a Fresh Scan
12258
+
12259
+ To perform a **rescan** of your repository (fetching a brand-new vulnerability report and updated fixes), include the additional parameter:
12260
+
12261
+ - **isRescan**: true
12262
+
12263
+ This will start a new analysis, discard any cached results.
12264
+
12265
+ \u26A0\uFE0F *Note:* A full rescan may take longer to complete than simply fetching additional fixes because your repository is re-uploaded and re-analyzed from scratch.
12094
12266
 
12095
- ${applyFixesPrompt(fixReport.fixes)}`;
12267
+ `;
12096
12268
  };
12097
12269
 
12098
12270
  // src/mcp/tools/checkForAvailableFixes/AvailableFixesService.ts
12099
12271
  var AvailableFixesService = class {
12100
12272
  constructor() {
12101
12273
  __publicField(this, "gqlClient", null);
12274
+ __publicField(this, "currentOffset", 0);
12102
12275
  }
12103
12276
  async initializeGqlClient() {
12104
12277
  if (!this.gqlClient) {
@@ -12106,13 +12279,30 @@ var AvailableFixesService = class {
12106
12279
  }
12107
12280
  return this.gqlClient;
12108
12281
  }
12109
- async checkForAvailableFixes(repoUrl, limit) {
12282
+ async checkForAvailableFixes({
12283
+ repoUrl,
12284
+ limit = 3,
12285
+ offset = 0
12286
+ }) {
12110
12287
  try {
12111
12288
  logDebug("Checking for available fixes", { repoUrl, limit });
12112
12289
  const gqlClient = await this.initializeGqlClient();
12113
12290
  logDebug("GQL client initialized");
12114
12291
  logDebug("querying for latest report", { repoUrl, limit });
12115
- const result = await gqlClient.getLatestReportByRepoUrl(repoUrl, limit);
12292
+ let effectiveOffset;
12293
+ if (offset !== void 0) {
12294
+ effectiveOffset = offset;
12295
+ } else if (this.currentOffset) {
12296
+ effectiveOffset = this.currentOffset ?? 0;
12297
+ } else {
12298
+ effectiveOffset = 0;
12299
+ }
12300
+ logDebug("effectiveOffset", { test: "j", effectiveOffset });
12301
+ const result = await gqlClient.getLatestReportByRepoUrl({
12302
+ repoUrl,
12303
+ limit,
12304
+ offset: effectiveOffset
12305
+ });
12116
12306
  logDebug("received latest report result", { result });
12117
12307
  if (!result) {
12118
12308
  logInfo("No report found for repository", { repoUrl });
@@ -12121,7 +12311,11 @@ var AvailableFixesService = class {
12121
12311
  logInfo("Successfully retrieved available fixes", {
12122
12312
  reportFound: true
12123
12313
  });
12124
- return fixesFoundPrompt(result);
12314
+ this.currentOffset = effectiveOffset + (result.fixes?.length || 0);
12315
+ return fixesFoundPrompt({
12316
+ fixReport: result,
12317
+ offset: this.currentOffset
12318
+ });
12125
12319
  } catch (error) {
12126
12320
  logError("Failed to check for available fixes", {
12127
12321
  error,
@@ -12139,29 +12333,31 @@ var CheckForAvailableFixesTool = class extends BaseTool {
12139
12333
  __publicField(this, "name", "check_for_available_fixes");
12140
12334
  __publicField(this, "displayName", "Check for Available Fixes");
12141
12335
  __publicField(this, "description", "Checks if there are any available fixes for vulnerabilities in the project");
12142
- __publicField(this, "inputSchema", z32.object({
12143
- path: z32.string().describe("Path to the project directory to check for available fixes"),
12144
- files: z32.array(z32.string()).optional().describe("Optional list of specific files to check"),
12145
- severity: z32.array(z32.string()).optional().describe("Optional list of severity levels to filter by"),
12146
- issueTypes: z32.array(z32.string()).optional().describe("Optional list of issue types to filter by"),
12147
- limit: z32.number().optional().describe("Optional maximum number of results to return")
12148
- }));
12149
- }
12150
- getJsonSchema() {
12151
- return {
12336
+ __publicField(this, "inputSchema", {
12152
12337
  type: "object",
12153
12338
  properties: {
12154
12339
  path: {
12155
12340
  type: "string",
12156
- description: "Path to the project directory to check for available fixes"
12341
+ description: "Path to the local git repository to check for available fixes"
12342
+ },
12343
+ offset: {
12344
+ type: "number",
12345
+ description: "[Optional] offset for pagination"
12157
12346
  },
12158
12347
  limit: {
12159
12348
  type: "number",
12160
- description: "Optional maximum number of results to return"
12349
+ description: "[Optional] maximum number of results to return"
12161
12350
  }
12162
12351
  },
12163
12352
  required: ["path"]
12164
- };
12353
+ });
12354
+ __publicField(this, "inputValidationSchema", z32.object({
12355
+ path: z32.string().describe(
12356
+ "Path to the local git repository to check for available fixes"
12357
+ ),
12358
+ offset: z32.number().optional().describe("Optional offset for pagination"),
12359
+ limit: z32.number().optional().describe("Optional maximum number of fixes to return")
12360
+ }));
12165
12361
  }
12166
12362
  async executeInternal(args) {
12167
12363
  const pathValidation = new PathValidation();
@@ -12185,10 +12381,11 @@ var CheckForAvailableFixesTool = class extends BaseTool {
12185
12381
  throw new Error("No origin URL found for the repository");
12186
12382
  }
12187
12383
  const availableFixesService = new AvailableFixesService();
12188
- const fixResult = await availableFixesService.checkForAvailableFixes(
12189
- originUrl,
12190
- args.limit
12191
- );
12384
+ const fixResult = await availableFixesService.checkForAvailableFixes({
12385
+ repoUrl: originUrl,
12386
+ limit: args.limit,
12387
+ offset: args.offset
12388
+ });
12192
12389
  logInfo("CheckForAvailableFixesTool execution completed successfully", {
12193
12390
  fixResult
12194
12391
  });
@@ -12203,6 +12400,9 @@ var CheckForAvailableFixesTool = class extends BaseTool {
12203
12400
  }
12204
12401
  };
12205
12402
 
12403
+ // src/mcp/tools/fixVulnerabilities/FixVulnerabilitiesTool.ts
12404
+ import z33 from "zod";
12405
+
12206
12406
  // src/mcp/services/FilePacking.ts
12207
12407
  import fs10 from "fs";
12208
12408
  import path12 from "path";
@@ -12243,158 +12443,62 @@ var FilePacking = class {
12243
12443
  }
12244
12444
  };
12245
12445
 
12246
- // src/mcp/tools/fixVulnerabilities/helpers/FixVulnerabilitiesResponsePrompts.ts
12247
- var noFixesFoundPrompt2 = `\u{1F389} **MOBB SECURITY SCAN COMPLETED SUCCESSFULLY** \u{1F389}
12248
-
12249
- ## Congratulations! No Vulnerabilities Found
12250
-
12251
- Your code has been thoroughly analyzed by Mobb's advanced security scanning engine, and we're pleased to report that **no security vulnerabilities were detected** in your codebase.
12252
-
12253
- ### \u{1F6E1}\uFE0F What This Means
12254
- - Your code follows secure coding practices
12255
- - No immediate security risks were identified
12256
- - Your application appears to be well-protected against common vulnerabilities
12257
-
12258
- ### \u2705 Scan Summary
12259
- - **Status:** Complete
12260
- - **Vulnerabilities Found:** 0
12261
- - **Security Rating:** Excellent
12262
- - **Action Required:** None
12263
-
12264
- ### \u{1F680} Next Steps
12265
- While no vulnerabilities were found in this scan:
12266
- 1. **Keep up the great work** with secure coding practices
12267
- 2. **Run regular scans** as your codebase evolves
12268
- 3. **Stay updated** with the latest security best practices
12269
- 4. **Consider periodic security reviews** for ongoing protection
12270
-
12271
- ### \u{1F4CA} Scan Details
12272
- This scan analyzed your code for common security issues including:
12273
- - SQL Injection vulnerabilities
12274
- - Cross-Site Scripting (XSS) flaws
12275
- - Authentication and authorization issues
12276
- - Input validation problems
12277
- - And many other security concerns
12278
-
12279
- **Well done on maintaining a secure codebase!** \u{1F3C6}`;
12280
- var fixesPrompt = (fixes) => {
12281
- const fix = fixes[0];
12282
- if (!fix) {
12283
- return noFixesFoundPrompt2;
12284
- }
12285
- return `Here are the fixes to the vulnerabilities discovered by Mobb MCP
12286
-
12287
- ${applyFixesPrompt(fixes)} `;
12288
- };
12289
- var failedToConnectToApiPrompt = `# CONNECTION ERROR: FAILED TO REACH MOBB API
12290
-
12291
- ## ANALYSIS SUMMARY
12292
- - **Status:** \u274C Failed
12293
- - **Issue Type:** Connection Error
12294
- - **Error Details:** Unable to establish connection to the Mobb API service
12295
-
12296
- ## TROUBLESHOOTING STEPS FOR THE USER
12297
-
12298
- The Mobb security scanning service is currently not reachable. This may be due to:
12299
-
12300
- 1. **Missing or invalid authentication credentials**
12301
- - Ensure the \`API_KEY\` environment variable is properly set with your valid Mobb authentication token
12302
- - Example: \`export API_KEY=your_mobb_api_key_here\`
12303
-
12304
- 2. **Incorrect API endpoint configuration**
12305
- - Check if the \`API_URL\` environment variable needs to be set to the correct Mobb service endpoint
12306
- - Example: \`export API_URL=https://api.mobb.ai/graphql\`
12307
-
12308
- 3. **Network connectivity issues**
12309
- - Verify your internet connection is working properly
12310
- - Check if any firewall or proxy settings might be blocking the connection
12311
-
12312
- 4. **Service outage**
12313
- - The Mobb service might be temporarily unavailable
12314
- - Please try again later or check the Mobb status page
12315
-
12316
- ## NEXT STEPS
12317
-
12318
- Please resolve the connection issue using the steps above and try running the security scan again.
12319
-
12320
- For additional assistance, please:
12321
- - Visit the Mobb documentation at https://docs.mobb.ai
12322
- - Contact Mobb support at support@mobb.ai
12323
-
12324
- `;
12325
- var failedToAuthenticatePrompt = `# AUTHENTICATION ERROR: MOBB LOGIN REQUIRED
12326
-
12327
- ## ANALYSIS SUMMARY
12328
- - **Status:** \u274C Failed
12329
- - **Issue Type:** Authentication Error
12330
- - **Error Details:** Unable to authenticate with the Mobb service
12331
-
12332
- ## AUTHENTICATION REQUIRED
12333
-
12334
- The Mobb security scanning service requires authentication before it can analyze your code for vulnerabilities. You need to:
12335
-
12336
- 1. **Login and authorize access to Mobb**
12337
- - A browser window should have opened to complete the authentication process
12338
- - If no browser window opened, please run the command again
12339
-
12340
- 2. **Create a Mobb account if you don't have one**
12341
- - If you don't already have a Mobb account, you'll need to sign up
12342
- - Visit https://app.mobb.ai/auth/signup to create your free account
12343
- - Use your work email for easier team collaboration
12344
-
12345
- 3. **Authorization flow**
12346
- - After logging in, you'll be asked to authorize the CLI tool
12347
- - This creates a secure token that allows the CLI to access Mobb services
12348
- - You only need to do this once per device
12349
-
12350
- ## TROUBLESHOOTING
12351
-
12352
- If you're experiencing issues with authentication:
12353
-
12354
- - Ensure you have an active internet connection
12355
- - Check that you can access https://app.mobb.ai in your browser
12356
- - Try running the command again with the \`--debug\` flag for more detailed output
12357
- - Make sure your browser isn't blocking pop-ups from the authentication window
12358
-
12359
- ## NEXT STEPS
12360
-
12361
- Please complete the authentication process and try running the security scan again.
12362
-
12363
- For additional assistance, please:
12364
- - Visit the Mobb documentation at https://docs.mobb.ai/cli/authentication
12365
- - Contact Mobb support at support@mobb.ai
12366
-
12367
- `;
12368
-
12369
12446
  // src/mcp/tools/fixVulnerabilities/FixVulnerabilitiesService.ts
12370
12447
  var VUL_REPORT_DIGEST_TIMEOUT_MS2 = 1e3 * 60 * 5;
12371
12448
  var VulnerabilityFixService = class {
12372
12449
  constructor() {
12373
12450
  __publicField(this, "gqlClient");
12374
12451
  __publicField(this, "filePacking");
12452
+ /**
12453
+ * Stores the fix report id that is created on the first run so that subsequent
12454
+ * calls can skip the expensive packing/uploading/scan flow and directly fetch
12455
+ * the analysis results.
12456
+ */
12457
+ __publicField(this, "storedFixReportId");
12458
+ __publicField(this, "currentOffset", 0);
12375
12459
  this.filePacking = new FilePacking();
12376
12460
  }
12377
- async processVulnerabilities(fileList, repositoryPath) {
12461
+ async processVulnerabilities({
12462
+ fileList,
12463
+ repositoryPath,
12464
+ offset,
12465
+ limit,
12466
+ isRescan = false
12467
+ }) {
12378
12468
  try {
12379
- this.validateFiles(fileList);
12380
12469
  this.gqlClient = await this.initializeGqlClient();
12381
- const repoUploadInfo = await this.initializeReport();
12382
- const zipBuffer = await this.packFiles(fileList, repositoryPath);
12383
- await this.uploadFiles(zipBuffer, repoUploadInfo);
12384
- const projectId = await this.getProjectId();
12385
- await this.runScan({
12386
- fixReportId: repoUploadInfo.fixReportId,
12387
- projectId
12388
- });
12389
- const fixes = await this.getReportFixes(repoUploadInfo.fixReportId);
12390
- return fixesPrompt(fixes);
12391
- } catch (error) {
12392
- if (error instanceof ApiConnectionError || error instanceof CliLoginError) {
12393
- return failedToConnectToApiPrompt;
12470
+ let fixReportId = this.storedFixReportId;
12471
+ if (!fixReportId || isRescan) {
12472
+ this.validateFiles(fileList);
12473
+ const repoUploadInfo = await this.initializeReport();
12474
+ fixReportId = repoUploadInfo.fixReportId;
12475
+ this.storedFixReportId = fixReportId;
12476
+ const zipBuffer = await this.packFiles(fileList, repositoryPath);
12477
+ await this.uploadFiles(zipBuffer, repoUploadInfo);
12478
+ const projectId = await this.getProjectId();
12479
+ await this.runScan({ fixReportId, projectId });
12394
12480
  }
12395
- if (error instanceof AuthenticationError || error instanceof FailedToGetApiTokenError) {
12396
- return failedToAuthenticatePrompt;
12481
+ let effectiveOffset;
12482
+ if (offset !== void 0) {
12483
+ effectiveOffset = offset;
12484
+ } else if (fixReportId) {
12485
+ effectiveOffset = this.currentOffset ?? 0;
12486
+ } else {
12487
+ effectiveOffset = 0;
12397
12488
  }
12489
+ logDebug("effectiveOffset", { effectiveOffset });
12490
+ const fixes = await this.getReportFixes(
12491
+ fixReportId,
12492
+ effectiveOffset,
12493
+ limit
12494
+ );
12495
+ this.currentOffset = effectiveOffset + (fixes.fixes?.length || 0);
12496
+ return fixesPrompt({
12497
+ fixes: fixes.fixes,
12498
+ totalCount: fixes.totalCount,
12499
+ offset: effectiveOffset
12500
+ });
12501
+ } catch (error) {
12398
12502
  const message = error.message;
12399
12503
  logError("Vulnerability processing failed", { error: message });
12400
12504
  throw error;
@@ -12483,7 +12587,7 @@ var VulnerabilityFixService = class {
12483
12587
  projectId,
12484
12588
  repoUrl: "",
12485
12589
  reference: "no-branch",
12486
- scanSource: "CLI" /* Cli */
12590
+ scanSource: "MCP" /* Mcp */
12487
12591
  };
12488
12592
  logInfo("Submitting vulnerability report");
12489
12593
  const submitRes = await this.gqlClient.submitVulnerabilityReport(
@@ -12510,34 +12614,63 @@ var VulnerabilityFixService = class {
12510
12614
  });
12511
12615
  logInfo("Analysis subscription completed");
12512
12616
  }
12513
- async getReportFixes(fixReportId) {
12617
+ async getReportFixes(fixReportId, offset, limit) {
12618
+ logDebug("getReportFixes", { fixReportId, offset, limit });
12514
12619
  if (!this.gqlClient) {
12515
12620
  throw new GqlClientError();
12516
12621
  }
12517
- const fixes = await this.gqlClient.getReportFixes(fixReportId);
12518
- logInfo("Fixes retrieved", { fixCount: fixes.length });
12519
- return fixes;
12622
+ const fixes = await this.gqlClient.getReportFixesPaginated({
12623
+ reportId: fixReportId,
12624
+ offset,
12625
+ limit
12626
+ });
12627
+ logInfo("Fixes retrieved", { fixCount: fixes?.fixes?.length });
12628
+ return {
12629
+ fixes: fixes?.fixes || [],
12630
+ totalCount: fixes?.totalCount || 0
12631
+ };
12520
12632
  }
12521
12633
  };
12522
12634
 
12523
12635
  // src/mcp/tools/fixVulnerabilities/FixVulnerabilitiesTool.ts
12524
- var FixVulnerabilitiesTool = class {
12636
+ var FixVulnerabilitiesTool = class extends BaseTool {
12525
12637
  constructor() {
12638
+ super(...arguments);
12526
12639
  __publicField(this, "name", "fix_vulnerabilities");
12527
- __publicField(this, "display_name", "fix_vulnerabilities");
12640
+ __publicField(this, "displayName", "Fix Vulnerabilities");
12528
12641
  __publicField(this, "description", "Scans the current code changes and returns fixes for potential vulnerabilities");
12642
+ __publicField(this, "inputValidationSchema", z33.object({
12643
+ path: z33.string().describe(
12644
+ "Path to the local git repository to check for available fixes"
12645
+ ),
12646
+ offset: z33.number().optional().describe("Optional offset for pagination"),
12647
+ limit: z33.number().optional().describe("Optional maximum number of results to return"),
12648
+ rescan: z33.boolean().optional().describe("Optional whether to rescan the repository")
12649
+ }));
12529
12650
  __publicField(this, "inputSchema", {
12530
12651
  type: "object",
12531
12652
  properties: {
12532
12653
  path: {
12533
12654
  type: "string",
12534
- description: "The path to the local git repository"
12655
+ description: "Path to the project directory to check for available fixes"
12656
+ },
12657
+ offset: {
12658
+ type: "number",
12659
+ description: "[Optional] offset for pagination"
12660
+ },
12661
+ limit: {
12662
+ type: "number",
12663
+ description: "[Optional] maximum number of results to return"
12664
+ },
12665
+ rescan: {
12666
+ type: "boolean",
12667
+ description: "[Optional] whether to rescan the repository"
12535
12668
  }
12536
12669
  },
12537
12670
  required: ["path"]
12538
12671
  });
12539
12672
  }
12540
- async execute(args) {
12673
+ async executeInternal(args) {
12541
12674
  logInfo("Executing tool: fix_vulnerabilities", { path: args.path });
12542
12675
  if (!args.path) {
12543
12676
  throw new Error("Invalid arguments: Missing required parameter 'path'");
@@ -12597,10 +12730,13 @@ var FixVulnerabilitiesTool = class {
12597
12730
  }
12598
12731
  try {
12599
12732
  const vulnerabilityFixService = new VulnerabilityFixService();
12600
- const fixResult = await vulnerabilityFixService.processVulnerabilities(
12601
- files,
12602
- args.path
12603
- );
12733
+ const fixResult = await vulnerabilityFixService.processVulnerabilities({
12734
+ fileList: files,
12735
+ repositoryPath: args.path,
12736
+ offset: args.offset,
12737
+ limit: args.limit,
12738
+ isRescan: args.rescan
12739
+ });
12604
12740
  const result = {
12605
12741
  content: [
12606
12742
  {
@@ -12640,28 +12776,22 @@ function createMcpServer() {
12640
12776
  name: "mobb-mcp",
12641
12777
  version: "1.0.0"
12642
12778
  });
12779
+ const enabledToolsEnv = process.env["TOOLS_ENABLED"];
12780
+ const enabledToolsSet = enabledToolsEnv ? new Set(
12781
+ enabledToolsEnv.split(",").map((t) => t.trim()).filter((t) => t.length > 0)
12782
+ ) : null;
12783
+ const registerIfEnabled = (tool) => {
12784
+ if (!enabledToolsSet || enabledToolsSet.has(tool.name)) {
12785
+ server.registerTool(tool);
12786
+ logDebug(`Registered tool: ${tool.name}`);
12787
+ } else {
12788
+ logDebug(`Skipping tool (disabled): ${tool.name}`);
12789
+ }
12790
+ };
12643
12791
  const fixVulnerabilitiesTool = new FixVulnerabilitiesTool();
12644
12792
  const checkForAvailableFixesTool = new CheckForAvailableFixesTool();
12645
- server.registerTool({
12646
- name: fixVulnerabilitiesTool.name,
12647
- definition: {
12648
- name: fixVulnerabilitiesTool.name,
12649
- display_name: fixVulnerabilitiesTool.display_name,
12650
- description: fixVulnerabilitiesTool.description,
12651
- inputSchema: fixVulnerabilitiesTool.inputSchema
12652
- },
12653
- execute: (args) => fixVulnerabilitiesTool.execute(args)
12654
- });
12655
- server.registerTool({
12656
- name: checkForAvailableFixesTool.name,
12657
- definition: {
12658
- name: checkForAvailableFixesTool.name,
12659
- display_name: checkForAvailableFixesTool.displayName,
12660
- description: checkForAvailableFixesTool.description,
12661
- inputSchema: checkForAvailableFixesTool.getJsonSchema()
12662
- },
12663
- execute: (args) => checkForAvailableFixesTool.execute(args)
12664
- });
12793
+ registerIfEnabled(fixVulnerabilitiesTool);
12794
+ registerIfEnabled(checkForAvailableFixesTool);
12665
12795
  logInfo("MCP server created and configured");
12666
12796
  return server;
12667
12797
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mobbdev",
3
- "version": "1.0.102",
3
+ "version": "1.0.104",
4
4
  "description": "Automated secure code remediation tool",
5
5
  "repository": "git+https://github.com/mobb-dev/bugsy.git",
6
6
  "main": "dist/index.js",