mobbdev 1.0.84 → 1.0.86

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 +1473 -48
  2. package/package.json +17 -7
package/dist/index.mjs CHANGED
@@ -7,7 +7,7 @@ var __export = (target, all) => {
7
7
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
8
8
 
9
9
  // src/index.ts
10
- import Debug20 from "debug";
10
+ import Debug21 from "debug";
11
11
  import { hideBin } from "yargs/helpers";
12
12
 
13
13
  // src/args/commands/convert_to_sarif.ts
@@ -259,6 +259,7 @@ var RepoNoTokenAccessError = class extends Error {
259
259
  import { z as z2 } from "zod";
260
260
 
261
261
  // src/features/analysis/scm/generates/client_generates.ts
262
+ import { graphql } from "msw";
262
263
  var FixQuestionInputType = /* @__PURE__ */ ((FixQuestionInputType2) => {
263
264
  FixQuestionInputType2["Number"] = "NUMBER";
264
265
  FixQuestionInputType2["Select"] = "SELECT";
@@ -553,16 +554,16 @@ var GetVulnerabilityReportPathsDocument = `
553
554
  }
554
555
  }
555
556
  `;
556
- var GetAnalysisDocument = `
557
- subscription getAnalysis($analysisId: uuid!) {
557
+ var GetAnalysisSubscriptionDocument = `
558
+ subscription getAnalysisSubscription($analysisId: uuid!) {
558
559
  analysis: fixReport_by_pk(id: $analysisId) {
559
560
  id
560
561
  state
561
562
  }
562
563
  }
563
564
  `;
564
- var GetAnalsyisDocument = `
565
- query getAnalsyis($analysisId: uuid!) {
565
+ var GetAnalysisDocument = `
566
+ query getAnalysis($analysisId: uuid!) {
566
567
  analysis: fixReport_by_pk(id: $analysisId) {
567
568
  id
568
569
  state
@@ -913,6 +914,37 @@ var AutoPrAnalysisDocument = `
913
914
  }
914
915
  }
915
916
  `;
917
+ var GetMcpFixesDocument = `
918
+ query GetMCPFixes($fixReportId: uuid!) {
919
+ fix(where: {fixReportId: {_eq: $fixReportId}}) {
920
+ id
921
+ confidence
922
+ safeIssueType
923
+ severityText
924
+ vulnerabilityReportIssues {
925
+ parsedIssueType
926
+ parsedSeverity
927
+ vulnerabilityReportIssueTags {
928
+ vulnerability_report_issue_tag_value
929
+ }
930
+ }
931
+ patchAndQuestions {
932
+ __typename
933
+ ... on FixData {
934
+ patch
935
+ patchOriginalEncodingBase64
936
+ extraContext {
937
+ extraContext {
938
+ key
939
+ value
940
+ }
941
+ fixDescription
942
+ }
943
+ }
944
+ }
945
+ }
946
+ }
947
+ `;
916
948
  var defaultWrapper = (action, _operationName, _operationType, _variables) => action();
917
949
  function getSdk(client, withWrapper = defaultWrapper) {
918
950
  return {
@@ -931,11 +963,11 @@ function getSdk(client, withWrapper = defaultWrapper) {
931
963
  GetVulnerabilityReportPaths(variables, requestHeaders) {
932
964
  return withWrapper((wrappedRequestHeaders) => client.request(GetVulnerabilityReportPathsDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "GetVulnerabilityReportPaths", "query", variables);
933
965
  },
934
- getAnalysis(variables, requestHeaders) {
935
- return withWrapper((wrappedRequestHeaders) => client.request(GetAnalysisDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "getAnalysis", "subscription", variables);
966
+ getAnalysisSubscription(variables, requestHeaders) {
967
+ return withWrapper((wrappedRequestHeaders) => client.request(GetAnalysisSubscriptionDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "getAnalysisSubscription", "subscription", variables);
936
968
  },
937
- getAnalsyis(variables, requestHeaders) {
938
- return withWrapper((wrappedRequestHeaders) => client.request(GetAnalsyisDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "getAnalsyis", "query", variables);
969
+ getAnalysis(variables, requestHeaders) {
970
+ return withWrapper((wrappedRequestHeaders) => client.request(GetAnalysisDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "getAnalysis", "query", variables);
939
971
  },
940
972
  getFixes(variables, requestHeaders) {
941
973
  return withWrapper((wrappedRequestHeaders) => client.request(GetFixesDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "getFixes", "query", variables);
@@ -978,6 +1010,9 @@ function getSdk(client, withWrapper = defaultWrapper) {
978
1010
  },
979
1011
  autoPrAnalysis(variables, requestHeaders) {
980
1012
  return withWrapper((wrappedRequestHeaders) => client.request(AutoPrAnalysisDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "autoPrAnalysis", "mutation", variables);
1013
+ },
1014
+ GetMCPFixes(variables, requestHeaders) {
1015
+ return withWrapper((wrappedRequestHeaders) => client.request(GetMcpFixesDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "GetMCPFixes", "query", variables);
981
1016
  }
982
1017
  };
983
1018
  }
@@ -4545,7 +4580,7 @@ async function getAdoSdk(params) {
4545
4580
  const git = await api2.getGitApi();
4546
4581
  try {
4547
4582
  const branchStatus = await git.getBranch(repo, branch, projectName);
4548
- if (!branchStatus || !branchStatus.commit) {
4583
+ if (!branchStatus?.commit) {
4549
4584
  console.log(`no branch status: ${JSON.stringify(branchStatus)}`);
4550
4585
  throw new InvalidRepoUrlError("no branch status");
4551
4586
  }
@@ -4596,7 +4631,7 @@ async function getAdoSdk(params) {
4596
4631
  const url = new URL(repoUrl);
4597
4632
  const origin2 = url.origin.toLowerCase().endsWith(".visualstudio.com") ? DEFUALT_ADO_ORIGIN : url.origin.toLowerCase();
4598
4633
  const params2 = `path=/&versionDescriptor[versionOptions]=0&versionDescriptor[versionType]=commit&versionDescriptor[version]=${branch}&resolveLfs=true&$format=zip&api-version=5.0&download=true`;
4599
- const path9 = [
4634
+ const path11 = [
4600
4635
  prefixPath,
4601
4636
  owner,
4602
4637
  projectName,
@@ -4607,7 +4642,7 @@ async function getAdoSdk(params) {
4607
4642
  "items",
4608
4643
  "items"
4609
4644
  ].filter(Boolean).join("/");
4610
- return new URL(`${path9}?${params2}`, origin2).toString();
4645
+ return new URL(`${path11}?${params2}`, origin2).toString();
4611
4646
  },
4612
4647
  async getAdoBranchList({ repoUrl }) {
4613
4648
  try {
@@ -4674,7 +4709,7 @@ async function getAdoSdk(params) {
4674
4709
  const results = await Promise.allSettled([
4675
4710
  (async () => {
4676
4711
  const res = await git.getBranch(repo, ref, projectName);
4677
- if (!res.commit || !res.commit.commitId) {
4712
+ if (!res.commit?.commitId) {
4678
4713
  throw new InvalidRepoUrlError("no commit on branch");
4679
4714
  }
4680
4715
  return {
@@ -4694,7 +4729,7 @@ async function getAdoSdk(params) {
4694
4729
  projectName
4695
4730
  );
4696
4731
  const commit = res[0];
4697
- if (!commit || !commit.commitId) {
4732
+ if (!commit?.commitId) {
4698
4733
  throw new Error("no commit");
4699
4734
  }
4700
4735
  return {
@@ -6065,14 +6100,14 @@ function getGithubSdk(params = {}) {
6065
6100
  };
6066
6101
  },
6067
6102
  async getGithubBlameRanges(params2) {
6068
- const { ref, gitHubUrl, path: path9 } = params2;
6103
+ const { ref, gitHubUrl, path: path11 } = params2;
6069
6104
  const { owner, repo } = parseGithubOwnerAndRepo(gitHubUrl);
6070
6105
  const res = await octokit.graphql(
6071
6106
  GET_BLAME_DOCUMENT,
6072
6107
  {
6073
6108
  owner,
6074
6109
  repo,
6075
- path: path9,
6110
+ path: path11,
6076
6111
  ref
6077
6112
  }
6078
6113
  );
@@ -6378,11 +6413,11 @@ var GithubSCMLib = class extends SCMLib {
6378
6413
  markdownComment: comment
6379
6414
  });
6380
6415
  }
6381
- async getRepoBlameRanges(ref, path9) {
6416
+ async getRepoBlameRanges(ref, path11) {
6382
6417
  this._validateUrl();
6383
6418
  return await this.githubSdk.getGithubBlameRanges({
6384
6419
  ref,
6385
- path: path9,
6420
+ path: path11,
6386
6421
  gitHubUrl: this.url
6387
6422
  });
6388
6423
  }
@@ -6784,13 +6819,13 @@ function parseGitlabOwnerAndRepo(gitlabUrl) {
6784
6819
  const { organization, repoName, projectPath } = parsingResult;
6785
6820
  return { owner: organization, repo: repoName, projectPath };
6786
6821
  }
6787
- async function getGitlabBlameRanges({ ref, gitlabUrl, path: path9 }, options) {
6822
+ async function getGitlabBlameRanges({ ref, gitlabUrl, path: path11 }, options) {
6788
6823
  const { projectPath } = parseGitlabOwnerAndRepo(gitlabUrl);
6789
6824
  const api2 = getGitBeaker({
6790
6825
  url: gitlabUrl,
6791
6826
  gitlabAuthToken: options?.gitlabAuthToken
6792
6827
  });
6793
- const resp = await api2.RepositoryFiles.allFileBlames(projectPath, path9, ref);
6828
+ const resp = await api2.RepositoryFiles.allFileBlames(projectPath, path11, ref);
6794
6829
  let lineNumber = 1;
6795
6830
  return resp.filter((range) => range.lines).map((range) => {
6796
6831
  const oldLineNumber = lineNumber;
@@ -6966,10 +7001,10 @@ var GitlabSCMLib = class extends SCMLib {
6966
7001
  markdownComment: comment
6967
7002
  });
6968
7003
  }
6969
- async getRepoBlameRanges(ref, path9) {
7004
+ async getRepoBlameRanges(ref, path11) {
6970
7005
  this._validateUrl();
6971
7006
  return await getGitlabBlameRanges(
6972
- { ref, path: path9, gitlabUrl: this.url },
7007
+ { ref, path: path11, gitlabUrl: this.url },
6973
7008
  {
6974
7009
  url: this.url,
6975
7010
  gitlabAuthToken: this.accessToken
@@ -7440,7 +7475,7 @@ var SCANNERS = {
7440
7475
  Semgrep: "semgrep",
7441
7476
  Datadog: "datadog"
7442
7477
  };
7443
- var scannerToVulnerability_Report_Vendor_Enum = {
7478
+ var scannerToVulnerabilityReportVendorEnum = {
7444
7479
  [SCANNERS.Checkmarx]: "checkmarx" /* Checkmarx */,
7445
7480
  [SCANNERS.Snyk]: "snyk" /* Snyk */,
7446
7481
  [SCANNERS.Sonarqube]: "sonarqube" /* Sonarqube */,
@@ -7662,7 +7697,8 @@ var mobbCliCommand = {
7662
7697
  scan: "scan",
7663
7698
  analyze: "analyze",
7664
7699
  review: "review",
7665
- convertToSarif: "convert-to-sarif"
7700
+ convertToSarif: "convert-to-sarif",
7701
+ mcp: "mcp"
7666
7702
  };
7667
7703
 
7668
7704
  // src/args/yargs.ts
@@ -7838,7 +7874,7 @@ function buildFixCommentBody({
7838
7874
  }
7839
7875
  const subTitle = validFixParseRes.success ? getCommitDescription({
7840
7876
  issueType: validFixParseRes.data.safeIssueType,
7841
- vendor: scannerToVulnerability_Report_Vendor_Enum[scanner],
7877
+ vendor: scannerToVulnerabilityReportVendorEnum[scanner],
7842
7878
  severity: validFixParseRes.data.severityText,
7843
7879
  guidances: getGuidances({
7844
7880
  questions: validFixParseRes.data.patchAndQuestions.questions.map(toQuestion),
@@ -7884,7 +7920,7 @@ function buildIssueCommentBody({
7884
7920
  const title = `# ${MobbIconMarkdown} Irrelevant issues were spotted - no action required \u{1F9F9}`;
7885
7921
  const subTitle = getCommitIssueDescription({
7886
7922
  issueType,
7887
- vendor: scannerToVulnerability_Report_Vendor_Enum[scanner],
7923
+ vendor: scannerToVulnerabilityReportVendorEnum[scanner],
7888
7924
  irrelevantIssueWithTags,
7889
7925
  fpDescription
7890
7926
  });
@@ -7963,7 +7999,7 @@ async function postIssueComment(params) {
7963
7999
  fpDescription
7964
8000
  } = params;
7965
8001
  const {
7966
- path: path9,
8002
+ path: path11,
7967
8003
  startLine,
7968
8004
  vulnerabilityReportIssue: {
7969
8005
  vulnerabilityReportIssueTags,
@@ -7978,7 +8014,7 @@ async function postIssueComment(params) {
7978
8014
  Refresh the page in order to see the changes.`,
7979
8015
  pull_number: pullRequest,
7980
8016
  commit_id: commitSha,
7981
- path: path9,
8017
+ path: path11,
7982
8018
  line: startLine
7983
8019
  });
7984
8020
  const commentId = commentRes.data.id;
@@ -8012,7 +8048,7 @@ async function postFixComment(params) {
8012
8048
  scanner
8013
8049
  } = params;
8014
8050
  const {
8015
- path: path9,
8051
+ path: path11,
8016
8052
  startLine,
8017
8053
  vulnerabilityReportIssue: { fixId, vulnerabilityReportIssueTags, category },
8018
8054
  vulnerabilityReportIssueId
@@ -8030,7 +8066,7 @@ async function postFixComment(params) {
8030
8066
  Refresh the page in order to see the changes.`,
8031
8067
  pull_number: pullRequest,
8032
8068
  commit_id: commitSha,
8033
- path: path9,
8069
+ path: path11,
8034
8070
  line: startLine
8035
8071
  });
8036
8072
  const commentId = commentRes.data.id;
@@ -8163,7 +8199,7 @@ async function addFixCommentsForPr({
8163
8199
  project: { organizationId }
8164
8200
  }
8165
8201
  } = getAnalysisRes;
8166
- if (!getAnalysisRes.repo || !getAnalysisRes.repo.commitSha || !getAnalysisRes.repo.pullRequest) {
8202
+ if (!getAnalysisRes.repo?.commitSha || !getAnalysisRes.repo.pullRequest) {
8167
8203
  throw new Error("repo not found");
8168
8204
  }
8169
8205
  const { commitSha, pullRequest } = getAnalysisRes.repo;
@@ -8631,9 +8667,6 @@ var GQLClient = class {
8631
8667
  }
8632
8668
  const { organization: org } = organizationToOrganizationRole;
8633
8669
  const project = projectName ? org?.projects.find((project2) => project2.name === projectName) ?? null : org?.projects[0];
8634
- if (!project?.id) {
8635
- throw new Error("Project not found");
8636
- }
8637
8670
  let projectId = project?.id;
8638
8671
  if (!projectId) {
8639
8672
  const createdProject = await this._clientSdk.CreateProject({
@@ -8642,6 +8675,9 @@ var GQLClient = class {
8642
8675
  });
8643
8676
  projectId = createdProject.createProject.projectId;
8644
8677
  }
8678
+ if (!project?.id) {
8679
+ throw new Error("Project not found");
8680
+ }
8645
8681
  return {
8646
8682
  organizationId: org.id,
8647
8683
  projectId
@@ -8806,7 +8842,7 @@ var GQLClient = class {
8806
8842
  async subscribeToAnalysis(params) {
8807
8843
  const { callbackStates } = params;
8808
8844
  return subscribe(
8809
- GetAnalysisDocument,
8845
+ GetAnalysisSubscriptionDocument,
8810
8846
  params.subscribeToAnalysisParams,
8811
8847
  async (resolve, reject, data) => {
8812
8848
  if (!data.analysis?.state || data.analysis?.state === "Failed" /* Failed */) {
@@ -8830,7 +8866,7 @@ var GQLClient = class {
8830
8866
  );
8831
8867
  }
8832
8868
  async getAnalysis(analysisId) {
8833
- const res = await this._clientSdk.getAnalsyis({
8869
+ const res = await this._clientSdk.getAnalysis({
8834
8870
  analysisId
8835
8871
  });
8836
8872
  if (!res.analysis) {
@@ -8897,7 +8933,7 @@ function endsWithAny(str, suffixes) {
8897
8933
  return str.endsWith(suffix);
8898
8934
  });
8899
8935
  }
8900
- function _get_manifest_files_suffixes() {
8936
+ function getManifestFilesSuffixes() {
8901
8937
  return ["package.json", "pom.xml"];
8902
8938
  }
8903
8939
  async function pack(srcDirPath, vulnFiles, isIncludeAllFiles = false) {
@@ -8938,7 +8974,7 @@ async function pack(srcDirPath, vulnFiles, isIncludeAllFiles = false) {
8938
8974
  for (const filepath of filepaths) {
8939
8975
  const absFilepath = path5.join(srcDirPath, filepath.toString());
8940
8976
  if (!isIncludeAllFiles) {
8941
- vulnFiles = vulnFiles.concat(_get_manifest_files_suffixes());
8977
+ vulnFiles = vulnFiles.concat(getManifestFilesSuffixes());
8942
8978
  if (!endsWithAny(
8943
8979
  absFilepath.toString().replaceAll(path5.win32.sep, path5.posix.sep),
8944
8980
  vulnFiles
@@ -9072,16 +9108,16 @@ function createSpawn({ args, processPath, name, cwd }, options) {
9072
9108
  return createChildProcess({ childProcess: child, name }, options);
9073
9109
  }
9074
9110
  function createChildProcess({ childProcess, name }, options) {
9075
- const debug20 = Debug14(`mobbdev:${name}`);
9111
+ const debug21 = Debug14(`mobbdev:${name}`);
9076
9112
  const { display } = options;
9077
9113
  return new Promise((resolve, reject) => {
9078
9114
  let out = "";
9079
9115
  const onData = (chunk) => {
9080
- debug20(`chunk received from ${name} std ${chunk}`);
9116
+ debug21(`chunk received from ${name} std ${chunk}`);
9081
9117
  out += chunk;
9082
9118
  };
9083
- if (!childProcess || !childProcess?.stdout || !childProcess?.stderr) {
9084
- debug20(`unable to fork ${name}`);
9119
+ if (!childProcess?.stdout || !childProcess?.stderr) {
9120
+ debug21(`unable to fork ${name}`);
9085
9121
  reject(new Error(`unable to fork ${name}`));
9086
9122
  }
9087
9123
  childProcess.stdout?.on("data", onData);
@@ -9091,11 +9127,11 @@ function createChildProcess({ childProcess, name }, options) {
9091
9127
  childProcess.stderr?.pipe(process2.stderr);
9092
9128
  }
9093
9129
  childProcess.on("exit", (code) => {
9094
- debug20(`${name} exit code ${code}`);
9130
+ debug21(`${name} exit code ${code}`);
9095
9131
  resolve({ message: out, code });
9096
9132
  });
9097
9133
  childProcess.on("error", (err) => {
9098
- debug20(`${name} error %o`, err);
9134
+ debug21(`${name} error %o`, err);
9099
9135
  reject(err);
9100
9136
  });
9101
9137
  });
@@ -10339,8 +10375,1392 @@ async function analyzeHandler(args) {
10339
10375
  await analyze(args, { skipPrompts: args.yes });
10340
10376
  }
10341
10377
 
10342
- // src/args/commands/review.ts
10378
+ // src/mcp/core/McpServer.ts
10379
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
10380
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
10381
+ import {
10382
+ CallToolRequestSchema,
10383
+ ListToolsRequestSchema
10384
+ } from "@modelcontextprotocol/sdk/types.js";
10385
+
10386
+ // src/mcp/Logger.ts
10387
+ var logglerUrl = "http://localhost:4444/log";
10388
+ var Logger = class {
10389
+ log(message, level = "info", data) {
10390
+ const logMessage = {
10391
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
10392
+ level,
10393
+ message,
10394
+ data
10395
+ };
10396
+ try {
10397
+ fetch(logglerUrl, {
10398
+ method: "POST",
10399
+ headers: { "Content-Type": "application/json" },
10400
+ body: JSON.stringify(logMessage)
10401
+ });
10402
+ } catch (error) {
10403
+ }
10404
+ }
10405
+ };
10406
+ var logger = new Logger();
10407
+ var logInfo = (message, data) => logger.log(message, "info", data);
10408
+ var logError = (message, data) => logger.log(message, "error", data);
10409
+ var logWarn = (message, data) => logger.log(message, "warn", data);
10410
+ var logDebug = (message, data) => logger.log(message, "debug", data);
10411
+ var Logger_default = logger.log;
10412
+
10413
+ // src/mcp/core/ToolRegistry.ts
10414
+ var ToolRegistry = class {
10415
+ constructor() {
10416
+ __publicField(this, "tools", /* @__PURE__ */ new Map());
10417
+ }
10418
+ registerTool(tool) {
10419
+ if (this.tools.has(tool.name)) {
10420
+ logWarn(`Tool ${tool.name} is already registered, overwriting`, {
10421
+ toolName: tool.name
10422
+ });
10423
+ }
10424
+ this.tools.set(tool.name, tool);
10425
+ logDebug(`Tool registered: ${tool.name}`, {
10426
+ toolName: tool.name,
10427
+ description: tool.definition.description
10428
+ });
10429
+ }
10430
+ getTool(name) {
10431
+ return this.tools.get(name);
10432
+ }
10433
+ getAllTools() {
10434
+ return Array.from(this.tools.values()).map((tool) => tool.definition);
10435
+ }
10436
+ getToolNames() {
10437
+ return Array.from(this.tools.keys());
10438
+ }
10439
+ hasTool(name) {
10440
+ return this.tools.has(name);
10441
+ }
10442
+ getToolCount() {
10443
+ return this.tools.size;
10444
+ }
10445
+ };
10446
+
10447
+ // src/mcp/core/McpServer.ts
10448
+ var McpServer = class {
10449
+ constructor(config4) {
10450
+ __publicField(this, "server");
10451
+ __publicField(this, "toolRegistry");
10452
+ __publicField(this, "isEventHandlersSetup", false);
10453
+ this.server = new Server(
10454
+ {
10455
+ name: config4.name,
10456
+ version: config4.version
10457
+ },
10458
+ {
10459
+ capabilities: {
10460
+ tools: {}
10461
+ }
10462
+ }
10463
+ );
10464
+ this.toolRegistry = new ToolRegistry();
10465
+ this.setupHandlers();
10466
+ this.setupProcessEventHandlers();
10467
+ logInfo("MCP server instance created", config4);
10468
+ }
10469
+ setupProcessEventHandlers() {
10470
+ if (this.isEventHandlersSetup) {
10471
+ logDebug("Process event handlers already setup, skipping");
10472
+ return;
10473
+ }
10474
+ const signals = {
10475
+ SIGINT: "MCP server interrupted",
10476
+ SIGTERM: "MCP server terminated",
10477
+ exit: "MCP server exiting",
10478
+ uncaughtException: "Uncaught exception in MCP server",
10479
+ unhandledRejection: "Unhandled promise rejection in MCP server",
10480
+ warning: "Warning in MCP server"
10481
+ };
10482
+ Object.entries(signals).forEach(([signal, message]) => {
10483
+ process.on(
10484
+ signal,
10485
+ (error) => {
10486
+ if (error && signal !== "exit") {
10487
+ logError(`${message}`, { error, signal });
10488
+ } else {
10489
+ logInfo(message, { signal });
10490
+ }
10491
+ if (signal === "SIGINT" || signal === "SIGTERM") {
10492
+ process.exit(0);
10493
+ }
10494
+ if (signal === "uncaughtException") {
10495
+ process.exit(1);
10496
+ }
10497
+ }
10498
+ );
10499
+ });
10500
+ this.isEventHandlersSetup = true;
10501
+ logDebug("Process event handlers registered");
10502
+ }
10503
+ createShutdownPromise() {
10504
+ return new Promise((resolve) => {
10505
+ const cleanup = () => {
10506
+ logInfo("Process shutdown initiated");
10507
+ resolve();
10508
+ };
10509
+ process.once("SIGINT", cleanup);
10510
+ process.once("SIGTERM", cleanup);
10511
+ });
10512
+ }
10513
+ setupHandlers() {
10514
+ this.server.setRequestHandler(
10515
+ ListToolsRequestSchema,
10516
+ async (request) => {
10517
+ logInfo("Received list_tools request", { params: request.params });
10518
+ const tools = this.toolRegistry.getAllTools();
10519
+ const response = { tools };
10520
+ logInfo("Returning list_tools response", {
10521
+ toolCount: tools.length,
10522
+ toolNames: tools.map((t) => t.name),
10523
+ response
10524
+ });
10525
+ return response;
10526
+ }
10527
+ );
10528
+ this.server.setRequestHandler(
10529
+ CallToolRequestSchema,
10530
+ async (request) => {
10531
+ const { name, arguments: args } = request.params;
10532
+ logInfo(`Received call tool request for ${name}`, { name, args });
10533
+ try {
10534
+ const tool = this.toolRegistry.getTool(name);
10535
+ if (!tool) {
10536
+ const errorMsg = `Unknown tool: ${name}`;
10537
+ logWarn(errorMsg, {
10538
+ name,
10539
+ availableTools: this.toolRegistry.getToolNames()
10540
+ });
10541
+ throw new Error(errorMsg);
10542
+ }
10543
+ logDebug(`Executing tool: ${name}`, { args });
10544
+ const response = await tool.execute(args);
10545
+ const serializedResponse = JSON.parse(JSON.stringify(response));
10546
+ logInfo(`Tool ${name} executed successfully`, {
10547
+ responseType: typeof response,
10548
+ hasContent: !!serializedResponse.content
10549
+ });
10550
+ return serializedResponse;
10551
+ } catch (error) {
10552
+ const errorMessage = error instanceof Error ? error.message : String(error);
10553
+ logError(`Error executing tool ${name}: ${errorMessage}`, {
10554
+ error,
10555
+ toolName: name,
10556
+ args
10557
+ });
10558
+ throw error;
10559
+ }
10560
+ }
10561
+ );
10562
+ logDebug("MCP server handlers registered");
10563
+ }
10564
+ registerTool(tool) {
10565
+ this.toolRegistry.registerTool({
10566
+ name: tool.name,
10567
+ definition: tool.definition,
10568
+ execute: tool.execute
10569
+ });
10570
+ logDebug(`Tool registered: ${tool.name}`);
10571
+ }
10572
+ async start() {
10573
+ try {
10574
+ logDebug("Starting MCP server");
10575
+ const transport = new StdioServerTransport();
10576
+ await this.server.connect(transport);
10577
+ logInfo("MCP server is running on stdin/stdout");
10578
+ process.stdin.resume();
10579
+ await this.createShutdownPromise();
10580
+ await this.stop();
10581
+ } catch (error) {
10582
+ logError("Failed to start MCP server", { error });
10583
+ throw error;
10584
+ }
10585
+ }
10586
+ async stop() {
10587
+ logInfo("MCP server shutting down");
10588
+ }
10589
+ };
10590
+
10591
+ // src/mcp/tools/fixVulnerabilities/FixVulnerabilitiesTool.ts
10592
+ import { z as z32 } from "zod";
10593
+
10594
+ // src/mcp/services/GitService.ts
10595
+ import { simpleGit as simpleGit4 } from "simple-git";
10596
+ var GitService = class {
10597
+ constructor(repositoryPath) {
10598
+ __publicField(this, "git");
10599
+ this.git = simpleGit4(repositoryPath, { binary: "git" });
10600
+ logDebug("Git service initialized", { repositoryPath });
10601
+ }
10602
+ /**
10603
+ * Validates that the path is a valid git repository
10604
+ */
10605
+ async validateRepository() {
10606
+ logDebug("Validating git repository");
10607
+ try {
10608
+ const isRepo = await this.git.checkIsRepo();
10609
+ if (!isRepo) {
10610
+ const error = "Path is not a valid git repository";
10611
+ logError(error);
10612
+ return { isValid: false, error };
10613
+ }
10614
+ logDebug("Git repository validation successful");
10615
+ return { isValid: true };
10616
+ } catch (error) {
10617
+ const errorMessage = `Failed to verify git repository: ${error.message}`;
10618
+ logError(errorMessage, { error });
10619
+ return { isValid: false, error: errorMessage };
10620
+ }
10621
+ }
10622
+ /**
10623
+ * Gets the current git status and returns changed files
10624
+ */
10625
+ async getChangedFiles() {
10626
+ logDebug("Getting git status");
10627
+ try {
10628
+ const status = await this.git.status();
10629
+ const files = status.files.map((file) => file.path);
10630
+ logInfo("Git status retrieved", {
10631
+ fileCount: files.length,
10632
+ files: files.slice(0, 10)
10633
+ // Log first 10 files to avoid spam
10634
+ });
10635
+ return { files, status };
10636
+ } catch (error) {
10637
+ const errorMessage = `Failed to get git status: ${error.message}`;
10638
+ logError(errorMessage, { error });
10639
+ throw new Error(errorMessage);
10640
+ }
10641
+ }
10642
+ };
10643
+
10644
+ // src/mcp/services/PathValidationService.ts
10343
10645
  import fs8 from "node:fs";
10646
+ import path9 from "node:path";
10647
+ var PathValidationService = class {
10648
+ /**
10649
+ * Validates a path for MCP usage - combines security and existence checks
10650
+ */
10651
+ async validatePath(inputPath) {
10652
+ logDebug("Validating MCP path", { inputPath });
10653
+ if (inputPath.includes("..")) {
10654
+ const error = `Path contains path traversal patterns: ${inputPath}`;
10655
+ logError(error);
10656
+ return { isValid: false, error };
10657
+ }
10658
+ const normalizedPath = path9.normalize(inputPath);
10659
+ if (normalizedPath.includes("..")) {
10660
+ const error = `Normalized path contains path traversal patterns: ${inputPath}`;
10661
+ logError(error);
10662
+ return { isValid: false, error };
10663
+ }
10664
+ const decodedPath = decodeURIComponent(inputPath);
10665
+ if (decodedPath.includes("..") || decodedPath !== inputPath) {
10666
+ const error = `Path contains encoded traversal attempts: ${inputPath}`;
10667
+ logError(error);
10668
+ return { isValid: false, error };
10669
+ }
10670
+ if (inputPath.includes("\0") || inputPath.includes("\0")) {
10671
+ const error = `Path contains dangerous characters: ${inputPath}`;
10672
+ logError(error);
10673
+ return { isValid: false, error };
10674
+ }
10675
+ logDebug("Path validation successful", { inputPath });
10676
+ logDebug("Checking path existence", { inputPath });
10677
+ try {
10678
+ await fs8.promises.access(inputPath);
10679
+ logDebug("Path exists and is accessible", { inputPath });
10680
+ return { isValid: true };
10681
+ } catch (error) {
10682
+ const errorMessage = `Path does not exist or is not accessible: ${inputPath}`;
10683
+ logError(errorMessage, { error });
10684
+ return { isValid: false, error: errorMessage };
10685
+ }
10686
+ }
10687
+ };
10688
+
10689
+ // src/mcp/tools/base/BaseTool.ts
10690
+ import { z as z31 } from "zod";
10691
+ var BaseTool = class {
10692
+ getDefinition() {
10693
+ return {
10694
+ name: this.name,
10695
+ display_name: this.displayName,
10696
+ description: this.description,
10697
+ inputSchema: {
10698
+ type: "object",
10699
+ properties: {
10700
+ path: {
10701
+ type: "string",
10702
+ description: "The path to the local git repository"
10703
+ }
10704
+ },
10705
+ required: ["path"]
10706
+ }
10707
+ };
10708
+ }
10709
+ async execute(args) {
10710
+ logInfo(`Executing tool: ${this.name}`, { args });
10711
+ const validatedArgs = this.validateInput(args);
10712
+ logDebug(`Tool ${this.name} input validation successful`, {
10713
+ validatedArgs
10714
+ });
10715
+ await this.validateAdditional(validatedArgs);
10716
+ try {
10717
+ const result = await this.executeInternal(validatedArgs);
10718
+ logInfo(`Tool ${this.name} executed successfully`);
10719
+ return result;
10720
+ } catch (error) {
10721
+ const errorMessage = error instanceof Error ? error.message : String(error);
10722
+ logError(`Tool ${this.name} execution failed: ${errorMessage}`, {
10723
+ error,
10724
+ args
10725
+ });
10726
+ return this.createErrorResponse(errorMessage);
10727
+ }
10728
+ }
10729
+ validateInput(args) {
10730
+ try {
10731
+ return this.inputSchema.parse(args);
10732
+ } catch (error) {
10733
+ if (error instanceof z31.ZodError) {
10734
+ const errorDetails = error.errors.map((e) => {
10735
+ const fieldPath = e.path.length > 0 ? e.path.join(".") : "root";
10736
+ const message = e.message === "Required" ? `Missing required parameter '${fieldPath}'` : `Invalid value for '${fieldPath}': ${e.message}`;
10737
+ return message;
10738
+ });
10739
+ const errorMessage = `Invalid arguments: ${errorDetails.join(", ")}`;
10740
+ throw new Error(errorMessage);
10741
+ }
10742
+ throw error;
10743
+ }
10744
+ }
10745
+ /**
10746
+ * Additional validation that should bubble up as MCP errors
10747
+ * Override this method in subclasses to add custom validation
10748
+ */
10749
+ async validateAdditional(_validatedArgs) {
10750
+ }
10751
+ createSuccessResponse(text) {
10752
+ return {
10753
+ content: [
10754
+ {
10755
+ type: "text",
10756
+ text
10757
+ }
10758
+ ]
10759
+ };
10760
+ }
10761
+ createErrorResponse(error) {
10762
+ return {
10763
+ content: [
10764
+ {
10765
+ type: "text",
10766
+ text: error
10767
+ }
10768
+ ]
10769
+ };
10770
+ }
10771
+ };
10772
+
10773
+ // src/mcp/services/FilePackingService.ts
10774
+ import fs9 from "node:fs";
10775
+ import path10 from "node:path";
10776
+ import AdmZip3 from "adm-zip";
10777
+ import { isBinary as isBinary2 } from "istextorbinary";
10778
+ var MAX_FILE_SIZE2 = 1024 * 1024 * 5;
10779
+ var EXCLUDED_FILE_PATTERNS = [
10780
+ // Configuration files
10781
+ ".json",
10782
+ ".yaml",
10783
+ ".yml",
10784
+ ".toml",
10785
+ ".ini",
10786
+ ".conf",
10787
+ ".config",
10788
+ ".xml",
10789
+ ".env",
10790
+ // Documentation
10791
+ ".md",
10792
+ ".txt",
10793
+ ".rst",
10794
+ ".adoc",
10795
+ // Lock/dependency files
10796
+ ".lock",
10797
+ // Images and media
10798
+ ".png",
10799
+ ".jpg",
10800
+ ".jpeg",
10801
+ ".gif",
10802
+ ".svg",
10803
+ ".ico",
10804
+ ".webp",
10805
+ ".bmp",
10806
+ ".tiff",
10807
+ // Fonts
10808
+ ".ttf",
10809
+ ".otf",
10810
+ ".woff",
10811
+ ".woff2",
10812
+ ".eot",
10813
+ // Archives
10814
+ ".zip",
10815
+ ".tar",
10816
+ ".gz",
10817
+ ".rar",
10818
+ ".7z",
10819
+ // Logs and databases
10820
+ ".log",
10821
+ ".db",
10822
+ ".sqlite",
10823
+ ".sql",
10824
+ // Certificates and keys
10825
+ ".pem",
10826
+ ".crt",
10827
+ ".key",
10828
+ ".p12",
10829
+ ".pfx",
10830
+ // IDE/Editor files
10831
+ ".editorconfig",
10832
+ ".sublime-project",
10833
+ ".sublime-workspace",
10834
+ // System files
10835
+ ".DS_Store",
10836
+ "Thumbs.db",
10837
+ // Coverage reports
10838
+ ".lcov",
10839
+ // Compiled/binary files
10840
+ ".exe",
10841
+ ".dll",
10842
+ ".so",
10843
+ ".dylib",
10844
+ ".class",
10845
+ ".pyc",
10846
+ ".pyo",
10847
+ ".o",
10848
+ ".obj",
10849
+ // Minified files
10850
+ ".min.js",
10851
+ ".min.css",
10852
+ ".min.html",
10853
+ // Test files
10854
+ ".test.js",
10855
+ ".test.ts",
10856
+ ".test.jsx",
10857
+ ".test.tsx",
10858
+ ".spec.js",
10859
+ ".spec.ts",
10860
+ ".spec.jsx",
10861
+ ".spec.tsx",
10862
+ // TypeScript declaration files
10863
+ ".d.ts",
10864
+ // Build/generated files
10865
+ ".bundle.js",
10866
+ ".chunk.js",
10867
+ // Build/CI files (exact filenames)
10868
+ "dockerfile",
10869
+ "jenkinsfile",
10870
+ // Lock files (ones without standard extensions)
10871
+ "go.sum",
10872
+ // Version control
10873
+ ".gitignore",
10874
+ ".gitattributes",
10875
+ ".gitmodules",
10876
+ ".gitkeep",
10877
+ ".keep",
10878
+ ".hgignore",
10879
+ // Node.js specific
10880
+ ".nvmrc",
10881
+ ".node-version",
10882
+ ".npmrc",
10883
+ ".yarnrc",
10884
+ ".pnpmfile.cjs",
10885
+ // Language version files
10886
+ ".ruby-version",
10887
+ ".python-version",
10888
+ ".rvmrc",
10889
+ ".rbenv-version",
10890
+ ".gvmrc",
10891
+ // Build tools and task runners
10892
+ "makefile",
10893
+ "rakefile",
10894
+ "gulpfile.js",
10895
+ "gruntfile.js",
10896
+ "webpack.config.js",
10897
+ "webpack.config.ts",
10898
+ "rollup.config.js",
10899
+ "vite.config.js",
10900
+ "vite.config.ts",
10901
+ "next.config.js",
10902
+ "nuxt.config.js",
10903
+ "tailwind.config.js",
10904
+ "postcss.config.js",
10905
+ // JavaScript/TypeScript config
10906
+ ".babelrc",
10907
+ ".babelrc.js",
10908
+ ".swcrc",
10909
+ ".browserslistrc",
10910
+ // Testing frameworks
10911
+ "jest.config.js",
10912
+ "jest.config.ts",
10913
+ "vitest.config.js",
10914
+ "karma.conf.js",
10915
+ "protractor.conf.js",
10916
+ "cypress.config.js",
10917
+ "playwright.config.js",
10918
+ ".nycrc",
10919
+ ".c8rc",
10920
+ // Linting/formatting configs
10921
+ ".eslintrc",
10922
+ ".eslintrc.js",
10923
+ ".prettierrc",
10924
+ ".prettierrc.js",
10925
+ ".stylelintrc",
10926
+ ".stylelintrc.js",
10927
+ // Package manager configs (ones without standard extensions)
10928
+ "pipfile",
10929
+ "gemfile",
10930
+ "go.mod",
10931
+ "project.clj",
10932
+ // Python specific
10933
+ "setup.py",
10934
+ "setup.cfg",
10935
+ "manifest.in",
10936
+ ".pythonrc",
10937
+ // Documentation files (ones without standard extensions)
10938
+ "readme",
10939
+ "changelog",
10940
+ "authors",
10941
+ "contributors",
10942
+ // License and legal (ones without standard extensions)
10943
+ "license",
10944
+ "notice",
10945
+ "copyright",
10946
+ // Web specific
10947
+ ".htaccess"
10948
+ ];
10949
+ var FilePackingService = class {
10950
+ isExcludedFileType(filepath) {
10951
+ const basename = path10.basename(filepath).toLowerCase();
10952
+ if (basename === ".env" || basename.startsWith(".env.")) {
10953
+ return true;
10954
+ }
10955
+ if (EXCLUDED_FILE_PATTERNS.some((pattern) => basename.endsWith(pattern))) {
10956
+ return true;
10957
+ }
10958
+ return false;
10959
+ }
10960
+ async packFiles(sourceDirectoryPath, filesToPack) {
10961
+ logInfo(`FilePackingService: packing files from ${sourceDirectoryPath}`);
10962
+ const zip = new AdmZip3();
10963
+ let packedFilesCount = 0;
10964
+ logInfo("FilePackingService: compressing files");
10965
+ for (const filepath of filesToPack) {
10966
+ const absoluteFilepath = path10.join(sourceDirectoryPath, filepath);
10967
+ if (this.isExcludedFileType(filepath)) {
10968
+ logInfo(
10969
+ `FilePackingService: ignoring ${filepath} because it is an excluded file type`
10970
+ );
10971
+ continue;
10972
+ }
10973
+ if (!fs9.existsSync(absoluteFilepath)) {
10974
+ logInfo(
10975
+ `FilePackingService: ignoring ${filepath} because it does not exist`
10976
+ );
10977
+ continue;
10978
+ }
10979
+ if (fs9.lstatSync(absoluteFilepath).size > MAX_FILE_SIZE2) {
10980
+ logInfo(
10981
+ `FilePackingService: ignoring ${filepath} because the size is > ${MAX_FILE_SIZE2 / (1024 * 1024)}MB`
10982
+ );
10983
+ continue;
10984
+ }
10985
+ let data;
10986
+ try {
10987
+ data = fs9.readFileSync(absoluteFilepath);
10988
+ } catch (fsError) {
10989
+ logInfo(
10990
+ `FilePackingService: failed to read ${filepath} from filesystem: ${fsError}`
10991
+ );
10992
+ continue;
10993
+ }
10994
+ if (isBinary2(null, data)) {
10995
+ logInfo(
10996
+ `FilePackingService: ignoring ${filepath} because it seems to be a binary file`
10997
+ );
10998
+ continue;
10999
+ }
11000
+ zip.addFile(filepath, data);
11001
+ packedFilesCount++;
11002
+ }
11003
+ const zipBuffer = zip.toBuffer();
11004
+ logInfo(
11005
+ `FilePackingService: read ${packedFilesCount} source files. total size: ${zipBuffer.length} bytes`
11006
+ );
11007
+ logInfo("FilePackingService: Files packed successfully");
11008
+ return zipBuffer;
11009
+ }
11010
+ };
11011
+
11012
+ // src/mcp/services/FileUploadService.ts
11013
+ import { HttpProxyAgent as HttpProxyAgent2 } from "http-proxy-agent";
11014
+ import { HttpsProxyAgent as HttpsProxyAgent3 } from "https-proxy-agent";
11015
+ var FileUploadService = class {
11016
+ getProxyAgent(url) {
11017
+ const HTTPS_PROXY2 = process.env["HTTPS_PROXY"];
11018
+ const HTTP_PROXY2 = process.env["HTTP_PROXY"];
11019
+ try {
11020
+ const parsedUrl = new URL(url);
11021
+ const isHttp = parsedUrl.protocol === "http:";
11022
+ const isHttps = parsedUrl.protocol === "https:";
11023
+ const proxy = isHttps ? HTTPS_PROXY2 : isHttp ? HTTP_PROXY2 : null;
11024
+ if (proxy) {
11025
+ logInfo(`FileUploadService: Using proxy ${proxy}`);
11026
+ return isHttps ? new HttpsProxyAgent3(proxy) : new HttpProxyAgent2(proxy);
11027
+ }
11028
+ } catch (err) {
11029
+ logInfo(
11030
+ `FileUploadService: Skipping proxy for ${url}. Reason: ${err.message}`
11031
+ );
11032
+ }
11033
+ return void 0;
11034
+ }
11035
+ async uploadFile(options) {
11036
+ const { file, url, uploadKey, uploadFields } = options;
11037
+ logInfo(`FileUploadService: upload file start ${url}`);
11038
+ logInfo(`FileUploadService: upload fields`, uploadFields);
11039
+ logInfo(`FileUploadService: upload key ${uploadKey}`);
11040
+ const {
11041
+ default: fetch5,
11042
+ File: File2,
11043
+ fileFrom: fileFrom2,
11044
+ FormData: FormData2
11045
+ } = await import("node-fetch");
11046
+ const form = new FormData2();
11047
+ Object.entries(uploadFields).forEach(([key, value]) => {
11048
+ form.append(key, value);
11049
+ });
11050
+ if (!form.has("key")) {
11051
+ form.append("key", uploadKey);
11052
+ }
11053
+ if (typeof file === "string") {
11054
+ logInfo(`FileUploadService: upload file from path ${file}`);
11055
+ form.append("file", await fileFrom2(file));
11056
+ } else {
11057
+ logInfo(`FileUploadService: upload file from buffer`);
11058
+ form.append("file", new File2([file], "file"));
11059
+ }
11060
+ const agent = this.getProxyAgent(url);
11061
+ const response = await fetch5(url, {
11062
+ method: "POST",
11063
+ body: form,
11064
+ agent
11065
+ });
11066
+ if (!response.ok) {
11067
+ logInfo(
11068
+ `FileUploadService: error from S3 ${response.body} ${response.status}`
11069
+ );
11070
+ throw new Error(`Failed to upload the file: ${response.status}`);
11071
+ }
11072
+ logInfo(`FileUploadService: upload file done`);
11073
+ }
11074
+ };
11075
+
11076
+ // src/mcp/tools/fixVulnerabilities/helpers/LLMResponsePrompts.ts
11077
+ function frienlyType(s) {
11078
+ const withoutUnderscores = s.replace(/_/g, " ");
11079
+ const result = withoutUnderscores.replace(/([a-z])([A-Z])/g, "$1 $2");
11080
+ return result.charAt(0).toUpperCase() + result.slice(1);
11081
+ }
11082
+ var noFixesFoundPrompt = `\u{1F389} **MOBB SECURITY SCAN COMPLETED SUCCESSFULLY** \u{1F389}
11083
+
11084
+ ## Congratulations! No Vulnerabilities Found
11085
+
11086
+ 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.
11087
+
11088
+ ### \u{1F6E1}\uFE0F What This Means
11089
+ - Your code follows secure coding practices
11090
+ - No immediate security risks were identified
11091
+ - Your application appears to be well-protected against common vulnerabilities
11092
+
11093
+ ### \u2705 Scan Summary
11094
+ - **Status:** Complete
11095
+ - **Vulnerabilities Found:** 0
11096
+ - **Security Rating:** Excellent
11097
+ - **Action Required:** None
11098
+
11099
+ ### \u{1F680} Next Steps
11100
+ While no vulnerabilities were found in this scan:
11101
+ 1. **Keep up the great work** with secure coding practices
11102
+ 2. **Run regular scans** as your codebase evolves
11103
+ 3. **Stay updated** with the latest security best practices
11104
+ 4. **Consider periodic security reviews** for ongoing protection
11105
+
11106
+ ### \u{1F4CA} Scan Details
11107
+ This scan analyzed your code for common security issues including:
11108
+ - SQL Injection vulnerabilities
11109
+ - Cross-Site Scripting (XSS) flaws
11110
+ - Authentication and authorization issues
11111
+ - Input validation problems
11112
+ - And many other security concerns
11113
+
11114
+ **Well done on maintaining a secure codebase!** \u{1F3C6}`;
11115
+ var fixesPrompt = (fixes) => {
11116
+ const fix = fixes[0];
11117
+ if (!fix) {
11118
+ return noFixesFoundPrompt;
11119
+ }
11120
+ const fixList = fixes.map((fix2) => {
11121
+ const vulnerabilityType = frienlyType(fix2.safeIssueType);
11122
+ const vulnerabilityDescription = fix2.patchAndQuestions?.__typename === "FixData" ? fix2.patchAndQuestions.extraContext?.fixDescription : void 0;
11123
+ const patch = fix2.patchAndQuestions?.__typename === "FixData" ? fix2.patchAndQuestions.patch : void 0;
11124
+ return {
11125
+ vulnerabilityType,
11126
+ vulnerabilityDescription,
11127
+ patch
11128
+ };
11129
+ });
11130
+ return `Here are the fixes to the vulnerabilities discovered by Mobb MCP
11131
+
11132
+ ## CRITICAL INSTRUCTIONS - READ CAREFULLY
11133
+
11134
+ You are an AI code assistant tasked with applying security vulnerability fixes. Follow these instructions EXACTLY:
11135
+
11136
+ ### 1. IMMEDIATE ACTION REQUIRED
11137
+ - **DO NOT ask for permission** - Apply the patches immediately
11138
+ - **DO NOT explain first** - Apply the patch, then explain what you did
11139
+ - **DO NOT modify any other code** - Only apply the exact changes shown in each patch
11140
+
11141
+ ### 2. HOW TO APPLY EACH PATCH
11142
+ For each fix below:
11143
+ 1. **Identify the target file** from the patch header (e.g., \`src/database/queries.js\`)
11144
+ 2. **Locate the exact lines** shown in the patch context
11145
+ 3. **Remove lines** that start with \`-\` (minus sign)
11146
+ 4. **Add lines** that start with \`+\` (plus sign)
11147
+ 5. **Keep unchanged lines** exactly as they are (lines without +/- prefix)
11148
+ 6. **Preserve indentation and formatting** exactly as shown
11149
+
11150
+ ### 3. PATCH FORMAT EXPLANATION
11151
+ - \`@@\` lines show line numbers and context
11152
+ - Lines starting with \`-\` should be REMOVED
11153
+ - Lines starting with \`+\` should be ADDED
11154
+ - Lines with no prefix should remain UNCHANGED
11155
+ - The patch shows surrounding context to help you locate the right place
11156
+
11157
+ ### 4. VALIDATION STEPS
11158
+ After applying each patch:
11159
+ 1. Verify the file syntax is correct
11160
+ 2. Ensure no unrelated code was modified
11161
+ 3. Confirm the vulnerability is addressed
11162
+
11163
+ ### 5. ERROR HANDLING
11164
+ If you cannot apply a patch:
11165
+ 1. Explain specifically what went wrong
11166
+ 2. Show the current state of the target lines
11167
+ 3. Ask for clarification on the specific issue
11168
+
11169
+ ---
11170
+
11171
+ # SECURITY FIXES TO APPLY
11172
+
11173
+ ${fixList.map(
11174
+ (fix2, index) => `
11175
+ ## Fix ${index + 1}: ${fix2.vulnerabilityType}
11176
+
11177
+ **\u{1F3AF} Target:** Apply this patch to fix a ${fix2.vulnerabilityType.toLowerCase()} vulnerability
11178
+
11179
+ **\u{1F4DD} Description:** ${fix2.vulnerabilityDescription || "Security vulnerability fix"}
11180
+
11181
+ **\u{1F527} Action Required:** Apply the following patch exactly as shown
11182
+
11183
+ **\u{1F4C1} Patch to Apply:**
11184
+ \`\`\`diff
11185
+ ${fix2.patch || "No patch available"}
11186
+ \`\`\`
11187
+
11188
+ **\u2705 Expected Result:** The vulnerability will be fixed and the code will be more secure
11189
+
11190
+ ---`
11191
+ ).join("\n")}
11192
+
11193
+ ## FINAL REMINDER
11194
+ - Apply ALL patches above in order
11195
+ - Do NOT ask for permission
11196
+ - Explain what you did AFTER applying the patches
11197
+ - If any patch fails, continue with the others and report issues at the end
11198
+ `;
11199
+ };
11200
+
11201
+ // src/mcp/tools/fixVulnerabilities/helpers/McpGQLClient.ts
11202
+ import { GraphQLClient as GraphQLClient2 } from "graphql-request";
11203
+ import { v4 as uuidv42 } from "uuid";
11204
+
11205
+ // src/mcp/constants.ts
11206
+ var DEFAULT_API_URL = "https://api.mobb.ai/v1/graphql";
11207
+ var API_KEY_HEADER_NAME2 = "x-mobb-key";
11208
+
11209
+ // src/mcp/tools/fixVulnerabilities/helpers/subscribe.ts
11210
+ import Debug20 from "debug";
11211
+ import { createClient as createClient2 } from "graphql-ws";
11212
+ import { HttpsProxyAgent as HttpsProxyAgent4 } from "https-proxy-agent";
11213
+ import WebSocket2 from "ws";
11214
+ var debug19 = Debug20("mobbdev:subscribe");
11215
+ var SUBSCRIPTION_TIMEOUT_MS2 = 30 * 60 * 1e3;
11216
+ function createWSClient2(options) {
11217
+ const proxy = options.url.startsWith("wss://") && process.env["HTTPS_PROXY"] ? new HttpsProxyAgent4(process.env["HTTPS_PROXY"]) : options.url.startsWith("ws://") && process.env["HTTP_PROXY"] ? new HttpsProxyAgent4(process.env["HTTP_PROXY"]) : null;
11218
+ debug19(
11219
+ `Using proxy: ${proxy ? "yes" : "no"} with url: ${options.url} and with proxy: ${process.env["HTTP_PROXY"]} for the websocket connection`
11220
+ );
11221
+ const CustomWebSocket = class extends WebSocket2 {
11222
+ constructor(address, protocols) {
11223
+ super(address, protocols, proxy ? { agent: proxy } : void 0);
11224
+ }
11225
+ };
11226
+ return createClient2({
11227
+ //this is needed to prevent AWS from killing the connection
11228
+ //currently our load balancer has a 29s idle timeout
11229
+ keepAlive: 1e4,
11230
+ url: options.url,
11231
+ webSocketImpl: proxy ? CustomWebSocket : options.websocket || WebSocket2,
11232
+ connectionParams: () => {
11233
+ return {
11234
+ headers: options.type === "apiKey" ? {
11235
+ [API_KEY_HEADER_NAME2]: options.apiKey
11236
+ } : { authorization: `Bearer ${options.token}` }
11237
+ };
11238
+ }
11239
+ });
11240
+ }
11241
+ function subscribe2(query, variables, callback, wsClientOptions) {
11242
+ return new Promise((resolve, reject) => {
11243
+ let timer = null;
11244
+ const { timeoutInMs = SUBSCRIPTION_TIMEOUT_MS2 } = wsClientOptions;
11245
+ const API_URL2 = process.env["API_URL"] || DEFAULT_API_URL;
11246
+ const client = createWSClient2({
11247
+ ...wsClientOptions,
11248
+ websocket: WebSocket2,
11249
+ url: API_URL2.replace("http", "ws")
11250
+ });
11251
+ const unsubscribe = client.subscribe(
11252
+ { query, variables },
11253
+ {
11254
+ next: (data) => {
11255
+ function callbackResolve(data2) {
11256
+ unsubscribe();
11257
+ if (timer) {
11258
+ clearTimeout(timer);
11259
+ }
11260
+ resolve(data2);
11261
+ }
11262
+ function callbackReject(data2) {
11263
+ unsubscribe();
11264
+ if (timer) {
11265
+ clearTimeout(timer);
11266
+ }
11267
+ reject(data2);
11268
+ }
11269
+ if (!data.data) {
11270
+ reject(
11271
+ new Error(
11272
+ `Broken data object from graphQL subscribe: ${JSON.stringify(
11273
+ data
11274
+ )} for query: ${query}`
11275
+ )
11276
+ );
11277
+ } else {
11278
+ callback(callbackResolve, callbackReject, data.data);
11279
+ }
11280
+ },
11281
+ error: (error) => {
11282
+ if (timer) {
11283
+ clearTimeout(timer);
11284
+ }
11285
+ reject(error);
11286
+ },
11287
+ complete: () => {
11288
+ return;
11289
+ }
11290
+ }
11291
+ );
11292
+ if (typeof timeoutInMs === "number") {
11293
+ timer = setTimeout(() => {
11294
+ unsubscribe();
11295
+ reject(
11296
+ new Error(
11297
+ `Timeout expired for graphQL subscribe query: ${query} with timeout: ${timeoutInMs}`
11298
+ )
11299
+ );
11300
+ }, timeoutInMs);
11301
+ }
11302
+ });
11303
+ }
11304
+
11305
+ // src/mcp/tools/fixVulnerabilities/helpers/McpGQLClient.ts
11306
+ var McpGQLClient = class {
11307
+ constructor(args) {
11308
+ __publicField(this, "client");
11309
+ __publicField(this, "clientSdk");
11310
+ __publicField(this, "apiKey");
11311
+ __publicField(this, "apiUrl");
11312
+ const API_URL2 = process.env["API_URL"] || DEFAULT_API_URL;
11313
+ this.apiKey = args.apiKey;
11314
+ this.apiUrl = API_URL2;
11315
+ this.client = new GraphQLClient2(API_URL2, {
11316
+ headers: { [API_KEY_HEADER_NAME2]: args.apiKey || "" },
11317
+ requestMiddleware: (request) => {
11318
+ const requestId = uuidv42();
11319
+ return {
11320
+ ...request,
11321
+ headers: {
11322
+ ...request.headers,
11323
+ "x-hasura-request-id": requestId
11324
+ }
11325
+ };
11326
+ }
11327
+ });
11328
+ this.clientSdk = getSdk(this.client);
11329
+ }
11330
+ getErrorContext() {
11331
+ return {
11332
+ endpoint: this.apiUrl,
11333
+ headers: {
11334
+ [API_KEY_HEADER_NAME2]: this.apiKey ? "[REDACTED]" : "undefined",
11335
+ "x-hasura-request-id": "[DYNAMIC]"
11336
+ }
11337
+ };
11338
+ }
11339
+ async verifyConnection() {
11340
+ try {
11341
+ logDebug("GraphQL: Calling Me query for connection verification");
11342
+ const result = await this.clientSdk.Me();
11343
+ logInfo("GraphQL: Me query successful", { result });
11344
+ return true;
11345
+ } catch (e) {
11346
+ logError("GraphQL: Me query failed", {
11347
+ error: e,
11348
+ ...this.getErrorContext()
11349
+ });
11350
+ if (e?.toString().startsWith("FetchError")) {
11351
+ console.error("Connection verification failed:", e);
11352
+ }
11353
+ return false;
11354
+ }
11355
+ }
11356
+ async uploadS3BucketInfo() {
11357
+ try {
11358
+ logDebug("GraphQL: Calling uploadS3BucketInfo mutation");
11359
+ const result = await this.clientSdk.uploadS3BucketInfo({
11360
+ fileName: "report.json"
11361
+ });
11362
+ logInfo("GraphQL: uploadS3BucketInfo successful", { result });
11363
+ return result;
11364
+ } catch (e) {
11365
+ logError("GraphQL: uploadS3BucketInfo failed", {
11366
+ error: e,
11367
+ ...this.getErrorContext()
11368
+ });
11369
+ throw e;
11370
+ }
11371
+ }
11372
+ async getAnalysis(analysisId) {
11373
+ try {
11374
+ logDebug("GraphQL: Calling getAnalysis query", { analysisId });
11375
+ const res = await this.clientSdk.getAnalysis({
11376
+ analysisId
11377
+ });
11378
+ logInfo("GraphQL: getAnalysis successful", { result: res });
11379
+ if (!res.analysis) {
11380
+ throw new Error(`Analysis not found: ${analysisId}`);
11381
+ }
11382
+ return res.analysis;
11383
+ } catch (e) {
11384
+ logError("GraphQL: getAnalysis failed", {
11385
+ error: e,
11386
+ analysisId,
11387
+ ...this.getErrorContext()
11388
+ });
11389
+ throw e;
11390
+ }
11391
+ }
11392
+ async submitVulnerabilityReport(variables) {
11393
+ try {
11394
+ logDebug("GraphQL: Calling SubmitVulnerabilityReport mutation", {
11395
+ variables
11396
+ });
11397
+ const result = await this.clientSdk.SubmitVulnerabilityReport(variables);
11398
+ logInfo("GraphQL: SubmitVulnerabilityReport successful", { result });
11399
+ return result;
11400
+ } catch (e) {
11401
+ logError("GraphQL: SubmitVulnerabilityReport failed", {
11402
+ error: e,
11403
+ variables,
11404
+ ...this.getErrorContext()
11405
+ });
11406
+ throw e;
11407
+ }
11408
+ }
11409
+ async subscribeToGetAnalysis(params) {
11410
+ try {
11411
+ logDebug("GraphQL: Starting GetAnalysis subscription", {
11412
+ params: params.subscribeToAnalysisParams
11413
+ });
11414
+ const { callbackStates } = params;
11415
+ const result = await subscribe2(
11416
+ GetAnalysisSubscriptionDocument,
11417
+ params.subscribeToAnalysisParams,
11418
+ async (resolve, reject, data) => {
11419
+ logDebug("GraphQL: GetAnalysis subscription data received", { data });
11420
+ if (!data.analysis?.state || data.analysis?.state === "Failed" /* Failed */) {
11421
+ logError("GraphQL: Analysis failed", {
11422
+ analysisId: data.analysis?.id,
11423
+ state: data.analysis?.state,
11424
+ ...this.getErrorContext()
11425
+ });
11426
+ reject(new Error(`Analysis failed with id: ${data.analysis?.id}`));
11427
+ return;
11428
+ }
11429
+ if (callbackStates.includes(data.analysis?.state)) {
11430
+ logInfo("GraphQL: Analysis state matches callback states", {
11431
+ analysisId: data.analysis.id,
11432
+ state: data.analysis.state,
11433
+ callbackStates
11434
+ });
11435
+ await params.callback(data.analysis.id);
11436
+ resolve(data);
11437
+ }
11438
+ },
11439
+ {
11440
+ apiKey: this.apiKey,
11441
+ type: "apiKey",
11442
+ timeoutInMs: params.timeoutInMs
11443
+ }
11444
+ );
11445
+ logInfo("GraphQL: GetAnalysis subscription completed", { result });
11446
+ return result;
11447
+ } catch (e) {
11448
+ logError("GraphQL: GetAnalysis subscription failed", {
11449
+ error: e,
11450
+ params: params.subscribeToAnalysisParams,
11451
+ ...this.getErrorContext()
11452
+ });
11453
+ throw e;
11454
+ }
11455
+ }
11456
+ async getProjectId() {
11457
+ try {
11458
+ const projectName = "MCP Scans";
11459
+ logDebug("GraphQL: Calling getOrgAndProjectId query", { projectName });
11460
+ const getOrgAndProjectIdResult = await this.clientSdk.getOrgAndProjectId({
11461
+ filters: {},
11462
+ limit: 1
11463
+ });
11464
+ logInfo("GraphQL: getOrgAndProjectId successful", {
11465
+ result: getOrgAndProjectIdResult
11466
+ });
11467
+ const [organizationToOrganizationRole] = getOrgAndProjectIdResult.organization_to_organization_role;
11468
+ if (!organizationToOrganizationRole) {
11469
+ throw new Error("Organization not found");
11470
+ }
11471
+ const { organization: org } = organizationToOrganizationRole;
11472
+ const project = projectName ? org?.projects.find((project2) => project2.name === projectName) ?? null : org?.projects[0];
11473
+ if (project?.id) {
11474
+ logInfo("GraphQL: Found existing project", {
11475
+ projectId: project.id,
11476
+ projectName
11477
+ });
11478
+ return project.id;
11479
+ }
11480
+ logDebug("GraphQL: Project not found, creating new project", {
11481
+ organizationId: org.id,
11482
+ projectName
11483
+ });
11484
+ const createdProject = await this.clientSdk.CreateProject({
11485
+ organizationId: org.id,
11486
+ projectName
11487
+ });
11488
+ logInfo("GraphQL: CreateProject successful", { result: createdProject });
11489
+ return createdProject.createProject.projectId;
11490
+ } catch (e) {
11491
+ logError("GraphQL: getProjectId failed", {
11492
+ error: e,
11493
+ ...this.getErrorContext()
11494
+ });
11495
+ throw e;
11496
+ }
11497
+ }
11498
+ async getReportFixes(fixReportId) {
11499
+ try {
11500
+ logDebug("GraphQL: Calling GetMCPFixes query", { fixReportId });
11501
+ const res = await this.clientSdk.GetMCPFixes({ fixReportId });
11502
+ logInfo("GraphQL: GetMCPFixes successful", {
11503
+ result: res,
11504
+ fixCount: res.fix?.length || 0
11505
+ });
11506
+ return res.fix;
11507
+ } catch (e) {
11508
+ logError("GraphQL: GetMCPFixes failed", {
11509
+ error: e,
11510
+ fixReportId,
11511
+ ...this.getErrorContext()
11512
+ });
11513
+ throw e;
11514
+ }
11515
+ }
11516
+ };
11517
+
11518
+ // src/mcp/tools/fixVulnerabilities/services/VulnerabilityFixService.ts
11519
+ var VUL_REPORT_DIGEST_TIMEOUT_MS2 = 1e3 * 60 * 5;
11520
+ var VulnerabilityFixService = class {
11521
+ constructor() {
11522
+ __publicField(this, "gqlClient");
11523
+ __publicField(this, "filePackingService");
11524
+ __publicField(this, "fileUploadService");
11525
+ this.filePackingService = new FilePackingService();
11526
+ this.fileUploadService = new FileUploadService();
11527
+ }
11528
+ async processVulnerabilities(fileList, repositoryPath) {
11529
+ try {
11530
+ this.validateFiles(fileList);
11531
+ const apiKey = this.validateApiKey();
11532
+ this.gqlClient = await this.initializeGqlClient(apiKey);
11533
+ const repoUploadInfo = await this.initializeReport();
11534
+ const zipBuffer = await this.packFiles(fileList, repositoryPath);
11535
+ await this.uploadFiles(zipBuffer, repoUploadInfo);
11536
+ const projectId = await this.getProjectId();
11537
+ await this.runScan({
11538
+ fixReportId: repoUploadInfo.fixReportId,
11539
+ projectId
11540
+ });
11541
+ const fixes = await this.getReportFixes(repoUploadInfo.fixReportId);
11542
+ return fixesPrompt(fixes);
11543
+ } catch (error) {
11544
+ const message = error.message;
11545
+ logError("Vulnerability processing failed", { error: message });
11546
+ throw error;
11547
+ }
11548
+ }
11549
+ validateFiles(fileList) {
11550
+ if (fileList.length === 0) {
11551
+ throw new Error("No files to fix");
11552
+ }
11553
+ }
11554
+ validateApiKey() {
11555
+ const apiKey = process.env["API_KEY"];
11556
+ if (!apiKey) {
11557
+ throw new Error("API_KEY environment variable is not set");
11558
+ }
11559
+ return apiKey;
11560
+ }
11561
+ async initializeGqlClient(apiKey) {
11562
+ const gqlClient = new McpGQLClient({
11563
+ apiKey,
11564
+ type: "apiKey"
11565
+ });
11566
+ const isConnected = await gqlClient.verifyConnection();
11567
+ if (!isConnected) {
11568
+ throw new Error("Failed to connect to the API. Please check your API_KEY");
11569
+ }
11570
+ return gqlClient;
11571
+ }
11572
+ async initializeReport() {
11573
+ if (!this.gqlClient) {
11574
+ throw new Error("GraphQL client not initialized");
11575
+ }
11576
+ try {
11577
+ const {
11578
+ uploadS3BucketInfo: { repoUploadInfo }
11579
+ } = await this.gqlClient.uploadS3BucketInfo();
11580
+ logInfo("Upload info retrieved", { uploadKey: repoUploadInfo?.uploadKey });
11581
+ return repoUploadInfo;
11582
+ } catch (error) {
11583
+ const message = error.message;
11584
+ throw new Error(`Error initializing report: ${message}`);
11585
+ }
11586
+ }
11587
+ async packFiles(fileList, repositoryPath) {
11588
+ try {
11589
+ const zipBuffer = await this.filePackingService.packFiles(
11590
+ repositoryPath,
11591
+ fileList
11592
+ );
11593
+ logInfo("Files packed successfully", { fileCount: fileList.length });
11594
+ return zipBuffer;
11595
+ } catch (error) {
11596
+ const message = error.message;
11597
+ throw new Error(`Error packing files: ${message}`);
11598
+ }
11599
+ }
11600
+ async uploadFiles(zipBuffer, repoUploadInfo) {
11601
+ if (!repoUploadInfo) {
11602
+ throw new Error("Upload info is required");
11603
+ }
11604
+ try {
11605
+ await this.fileUploadService.uploadFile({
11606
+ file: zipBuffer,
11607
+ url: repoUploadInfo.url,
11608
+ uploadFields: JSON.parse(repoUploadInfo.uploadFieldsJSON),
11609
+ uploadKey: repoUploadInfo.uploadKey
11610
+ });
11611
+ logInfo("File uploaded successfully");
11612
+ } catch (error) {
11613
+ logError("File upload failed", { error: error.message });
11614
+ throw new Error(`Failed to upload the file: ${error.message}`);
11615
+ }
11616
+ }
11617
+ async getProjectId() {
11618
+ if (!this.gqlClient) {
11619
+ throw new Error("GraphQL client not initialized");
11620
+ }
11621
+ const projectId = await this.gqlClient.getProjectId();
11622
+ logInfo("Project ID retrieved", { projectId });
11623
+ return projectId;
11624
+ }
11625
+ async runScan(params) {
11626
+ if (!this.gqlClient) {
11627
+ throw new Error("GraphQL client not initialized");
11628
+ }
11629
+ const { fixReportId, projectId } = params;
11630
+ logInfo("Starting scan", { fixReportId, projectId });
11631
+ const submitVulnerabilityReportVariables = {
11632
+ fixReportId,
11633
+ projectId,
11634
+ repoUrl: "",
11635
+ reference: "no-branch",
11636
+ scanSource: "CLI" /* Cli */
11637
+ };
11638
+ logInfo("Submitting vulnerability report");
11639
+ const submitRes = await this.gqlClient.submitVulnerabilityReport(
11640
+ submitVulnerabilityReportVariables
11641
+ );
11642
+ if (submitRes.submitVulnerabilityReport.__typename !== "VulnerabilityReport") {
11643
+ logError("Vulnerability report submission failed", {
11644
+ response: submitRes
11645
+ });
11646
+ throw new Error("\u{1F575}\uFE0F\u200D\u2642\uFE0F Mobb analysis failed");
11647
+ }
11648
+ logInfo("Vulnerability report submitted successfully", {
11649
+ analysisId: submitRes.submitVulnerabilityReport.fixReportId
11650
+ });
11651
+ logInfo("Starting analysis subscription");
11652
+ await this.gqlClient.subscribeToGetAnalysis({
11653
+ subscribeToAnalysisParams: {
11654
+ analysisId: submitRes.submitVulnerabilityReport.fixReportId
11655
+ },
11656
+ callback: () => {
11657
+ },
11658
+ callbackStates: ["Finished" /* Finished */],
11659
+ timeoutInMs: VUL_REPORT_DIGEST_TIMEOUT_MS2
11660
+ });
11661
+ logInfo("Analysis subscription completed");
11662
+ }
11663
+ async getReportFixes(fixReportId) {
11664
+ if (!this.gqlClient) {
11665
+ throw new Error("GraphQL client not initialized");
11666
+ }
11667
+ const fixes = await this.gqlClient.getReportFixes(fixReportId);
11668
+ logInfo("Fixes retrieved", { fixCount: fixes.length });
11669
+ return fixes;
11670
+ }
11671
+ };
11672
+
11673
+ // src/mcp/tools/fixVulnerabilities/FixVulnerabilitiesTool.ts
11674
+ var FixVulnerabilitiesInputSchema = z32.object({
11675
+ path: z32.string().min(1, "Path is required and must be a string")
11676
+ });
11677
+ var FixVulnerabilitiesTool = class extends BaseTool {
11678
+ constructor() {
11679
+ super(...arguments);
11680
+ __publicField(this, "name", "fix_vulnerabilities");
11681
+ __publicField(this, "displayName", "fix_vulnerabilities");
11682
+ __publicField(this, "description", "Scans the current code changes and returns fixes for potential vulnerabilities");
11683
+ __publicField(this, "inputSchema", FixVulnerabilitiesInputSchema);
11684
+ }
11685
+ async validateAdditional(validatedArgs) {
11686
+ const { path: path11 } = validatedArgs;
11687
+ const pathValidationService = new PathValidationService();
11688
+ const pathValidation = await pathValidationService.validatePath(path11);
11689
+ if (!pathValidation.isValid) {
11690
+ const errorMessage = `Invalid path: potential security risk detected in path: ${path11}`;
11691
+ throw new Error(errorMessage);
11692
+ }
11693
+ const gitService = new GitService(path11);
11694
+ const gitValidation = await gitService.validateRepository();
11695
+ if (!gitValidation.isValid) {
11696
+ throw new Error(gitValidation.error || "Git repository validation failed");
11697
+ }
11698
+ }
11699
+ async executeInternal(validatedArgs) {
11700
+ const { path: path11 } = validatedArgs;
11701
+ const gitService = new GitService(path11);
11702
+ const gitResult = await gitService.getChangedFiles();
11703
+ if (gitResult.files.length === 0) {
11704
+ return this.createSuccessResponse(
11705
+ "No changed files found in the git repository. The vulnerability scanner analyzes modified, added, or staged files. Make some changes to your code and try again."
11706
+ );
11707
+ }
11708
+ const vulnerabilityFixService = new VulnerabilityFixService();
11709
+ const fixResult = await vulnerabilityFixService.processVulnerabilities(
11710
+ gitResult.files,
11711
+ path11
11712
+ );
11713
+ return this.createSuccessResponse(fixResult);
11714
+ }
11715
+ };
11716
+
11717
+ // src/mcp/index.ts
11718
+ function createMcpServer() {
11719
+ logDebug("Creating MCP server");
11720
+ const server = new McpServer({
11721
+ name: "mobb-mcp",
11722
+ version: "1.0.0"
11723
+ });
11724
+ const fixVulnerabilitiesTool = new FixVulnerabilitiesTool();
11725
+ server.registerTool({
11726
+ name: fixVulnerabilitiesTool.name,
11727
+ definition: fixVulnerabilitiesTool.getDefinition(),
11728
+ execute: (args) => fixVulnerabilitiesTool.execute(args)
11729
+ });
11730
+ logInfo("MCP server created and configured");
11731
+ return server;
11732
+ }
11733
+ async function startMcpServer() {
11734
+ try {
11735
+ logDebug("Initializing MCP server");
11736
+ const server = createMcpServer();
11737
+ await server.start();
11738
+ } catch (error) {
11739
+ logError("Failed to start MCP server", { error });
11740
+ throw error;
11741
+ }
11742
+ }
11743
+
11744
+ // src/args/commands/mcp.ts
11745
+ var mcpBuilder = (yargs2) => {
11746
+ return yargs2.example("$0 mcp", "Launch the MCP server").option("debug", {
11747
+ alias: "d",
11748
+ type: "boolean",
11749
+ description: "Run in debug mode with communication logging",
11750
+ default: false
11751
+ }).strict();
11752
+ };
11753
+ var mcpHandler = async (_args) => {
11754
+ try {
11755
+ await startMcpServer();
11756
+ } catch (error) {
11757
+ console.error("Failed to start MCP server:", error);
11758
+ process.exit(1);
11759
+ }
11760
+ };
11761
+
11762
+ // src/args/commands/review.ts
11763
+ import fs10 from "node:fs";
10344
11764
  import chalk9 from "chalk";
10345
11765
  function reviewBuilder(yargs2) {
10346
11766
  return yargs2.option("f", {
@@ -10377,7 +11797,7 @@ function reviewBuilder(yargs2) {
10377
11797
  ).help();
10378
11798
  }
10379
11799
  function validateReviewOptions(argv) {
10380
- if (!fs8.existsSync(argv.f)) {
11800
+ if (!fs10.existsSync(argv.f)) {
10381
11801
  throw new CliError(`
10382
11802
  Can't access ${chalk9.bold(argv.f)}`);
10383
11803
  }
@@ -10498,6 +11918,11 @@ var parseArgs = async (args) => {
10498
11918
  chalk10.bold("Convert an existing SAST report to SARIF format."),
10499
11919
  convertToSarifBuilder,
10500
11920
  convertToSarifHandler
11921
+ ).command(
11922
+ mobbCliCommand.mcp,
11923
+ chalk10.bold("Launch the MCP (Model Context Protocol) server."),
11924
+ mcpBuilder,
11925
+ mcpHandler
10501
11926
  ).example(
10502
11927
  "npx mobbdev@latest scan -r https://github.com/WebGoat/WebGoat",
10503
11928
  "Scan an existing repository"
@@ -10510,13 +11935,13 @@ var parseArgs = async (args) => {
10510
11935
  };
10511
11936
 
10512
11937
  // src/index.ts
10513
- var debug19 = Debug20("mobbdev:index");
11938
+ var debug20 = Debug21("mobbdev:index");
10514
11939
  async function run() {
10515
11940
  return parseArgs(hideBin(process.argv));
10516
11941
  }
10517
11942
  (async () => {
10518
11943
  try {
10519
- debug19("Bugsy CLI v%s running...", packageJson.version);
11944
+ debug20("Bugsy CLI v%s running...", packageJson.version);
10520
11945
  await run();
10521
11946
  process.exit(0);
10522
11947
  } catch (err) {