From 9819d090fe54b8fcd771b2917747a083c7f9835a Mon Sep 17 00:00:00 2001 From: seth jaksik Date: Mon, 7 Jul 2025 15:42:43 -0500 Subject: [PATCH 1/4] sca scan logic --- src/semgrep_mcp/server.py | 43 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/src/semgrep_mcp/server.py b/src/semgrep_mcp/server.py index 48642c8..1d214a4 100755 --- a/src/semgrep_mcp/server.py +++ b/src/semgrep_mcp/server.py @@ -273,7 +273,7 @@ def create_temp_files_from_code_content(code_files: list[CodeFile]) -> str: ) from e -def get_semgrep_scan_args(temp_dir: str, config: str | None = None) -> list[str]: +def get_semgrep_scan_args(temp_dir: str, config: str | None = None, scan_type: str = "code") -> list[str]: """ Builds command arguments for semgrep scan @@ -288,9 +288,37 @@ def get_semgrep_scan_args(temp_dir: str, config: str | None = None) -> list[str] # Build command arguments and just run semgrep scan # if no config is provided to allow for either the default "auto" # or whatever the logged in config is - args = ["scan", "--json", "--experimental"] # avoid the extra exec + args = ["ci", "--json", "--dry-run"] # avoid the extra exec + api_token = os.environ.get("SEMGREP_API_TOKEN") if config: args.extend(["--config", config]) + match scan_type: + case "code": + args.append("--code") + case "supply-chain": + if not api_token: + raise McpError( + ErrorData( + code=INVALID_PARAMS, + message="SEMGREP_API_TOKEN environment variable must be set to use this tool." + "Create a token at semgrep.dev to continue.", + ) + ) + args.append("--supply-chain") + case "secret": + if not api_token: + raise McpError( + ErrorData( + code=INVALID_PARAMS, + message="SEMGREP_API_TOKEN environment variable must be set to use this tool." + "Create a token at semgrep.dev to continue.", + ) + ) + args.append("--secrets") + case _: + raise McpError( + ErrorData(code=INVALID_PARAMS, message=f"Invalid scan type: {scan_type}") + ) args.append(temp_dir) return args @@ -699,6 +727,7 @@ async def semgrep_scan_with_custom_rule( async def semgrep_scan( code_files: list[CodeFile] = CODE_FILES_FIELD, config: str | None = CONFIG_FIELD, + scan_type: str = "code" ) -> SemgrepScanResult: """ Runs a Semgrep scan on provided code content and returns the findings in JSON format @@ -706,6 +735,14 @@ async def semgrep_scan( Use this tool when you need to: - scan code files for security vulnerabilities - scan code files for other issues + + Args: + code_files: The code files to scan. + config: The Semgrep config to use. + scan_type: The type of scan to run. + - "code": Scan code files. + - "supply-chain": Scan code files for CI/CD. + - "secrets": Scan code files for secrets. """ # Validate config config = validate_config(config) @@ -716,7 +753,7 @@ async def semgrep_scan( try: # Create temporary files from code content temp_dir = create_temp_files_from_code_content(code_files) - args = get_semgrep_scan_args(temp_dir, config) + args = get_semgrep_scan_args(temp_dir, config, scan_type) output = await run_semgrep(args) results: SemgrepScanResult = SemgrepScanResult.model_validate_json(output) remove_temp_dir_from_results(results, temp_dir) From 7b9099e9690aa42295ab691a9e79df0e5990b23d Mon Sep 17 00:00:00 2001 From: seth jaksik Date: Tue, 8 Jul 2025 12:51:09 -0500 Subject: [PATCH 2/4] change check to ci and add ability to choose scan type --- src/semgrep_mcp/server.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/semgrep_mcp/server.py b/src/semgrep_mcp/server.py index 1d214a4..68b317c 100755 --- a/src/semgrep_mcp/server.py +++ b/src/semgrep_mcp/server.py @@ -273,7 +273,9 @@ def create_temp_files_from_code_content(code_files: list[CodeFile]) -> str: ) from e -def get_semgrep_scan_args(temp_dir: str, config: str | None = None, scan_type: str = "code") -> list[str]: +def get_semgrep_scan_args( + temp_dir: str, config: str | None = None, scan_type: str = "code" +) -> list[str]: """ Builds command arguments for semgrep scan @@ -290,8 +292,8 @@ def get_semgrep_scan_args(temp_dir: str, config: str | None = None, scan_type: s # or whatever the logged in config is args = ["ci", "--json", "--dry-run"] # avoid the extra exec api_token = os.environ.get("SEMGREP_API_TOKEN") - if config: - args.extend(["--config", config]) + # if config: + # args.extend(["--config", config]) match scan_type: case "code": args.append("--code") @@ -319,7 +321,7 @@ def get_semgrep_scan_args(temp_dir: str, config: str | None = None, scan_type: s raise McpError( ErrorData(code=INVALID_PARAMS, message=f"Invalid scan type: {scan_type}") ) - args.append(temp_dir) + args.extend(["--include", temp_dir]) return args @@ -727,7 +729,7 @@ async def semgrep_scan_with_custom_rule( async def semgrep_scan( code_files: list[CodeFile] = CODE_FILES_FIELD, config: str | None = CONFIG_FIELD, - scan_type: str = "code" + scan_type: str = "code", ) -> SemgrepScanResult: """ Runs a Semgrep scan on provided code content and returns the findings in JSON format @@ -735,7 +737,7 @@ async def semgrep_scan( Use this tool when you need to: - scan code files for security vulnerabilities - scan code files for other issues - + Args: code_files: The code files to scan. config: The Semgrep config to use. @@ -1007,13 +1009,12 @@ async def get_semgrep_rule_yaml(rule_id: str = RULE_ID_FIELD) -> str: ErrorData(code=INTERNAL_ERROR, message=f"Error loading Semgrep rule schema: {e!s}") ) from e + @mcp.custom_route("/health", methods=["GET"]) async def health(request: Request) -> JSONResponse: """Health check endpoint""" - return JSONResponse({ - "status": "ok", - "version": __version__ - }) + return JSONResponse({"status": "ok", "version": __version__}) + # --------------------------------------------------------------------------------- # MCP Server Entry Point From 43b85988a8e30f1b93c9cd2bc0438f5391064dba Mon Sep 17 00:00:00 2001 From: Flavio Percoco <13816+flaper87@users.noreply.github.com> Date: Thu, 10 Jul 2025 20:56:04 +0200 Subject: [PATCH 3/4] Apply suggestions from code review --- src/semgrep_mcp/server.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/semgrep_mcp/server.py b/src/semgrep_mcp/server.py index 72c4e24..03b4d81 100755 --- a/src/semgrep_mcp/server.py +++ b/src/semgrep_mcp/server.py @@ -295,8 +295,6 @@ def get_semgrep_scan_args( # or whatever the logged in config is args = ["ci", "--json", "--dry-run"] # avoid the extra exec api_token = os.environ.get("SEMGREP_API_TOKEN") - # if config: - # args.extend(["--config", config]) match scan_type: case "code": args.append("--code") @@ -305,7 +303,8 @@ def get_semgrep_scan_args( raise McpError( ErrorData( code=INVALID_PARAMS, - message="SEMGREP_API_TOKEN environment variable must be set to use this tool." + message=("SEMGREP_API_TOKEN environment variable " + "must be set to use this tool.") "Create a token at semgrep.dev to continue.", ) ) @@ -315,7 +314,8 @@ def get_semgrep_scan_args( raise McpError( ErrorData( code=INVALID_PARAMS, - message="SEMGREP_API_TOKEN environment variable must be set to use this tool." + message=("SEMGREP_API_TOKEN environment variable " + "must be set to use this tool.") "Create a token at semgrep.dev to continue.", ) ) From b245d522ee5d6f21e0b6720c5191b304ad81f59b Mon Sep 17 00:00:00 2001 From: Flavio Percoco <13816+flaper87@users.noreply.github.com> Date: Thu, 10 Jul 2025 21:00:54 +0200 Subject: [PATCH 4/4] Update server.py --- src/semgrep_mcp/server.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/semgrep_mcp/server.py b/src/semgrep_mcp/server.py index 03b4d81..2054f46 100755 --- a/src/semgrep_mcp/server.py +++ b/src/semgrep_mcp/server.py @@ -303,9 +303,9 @@ def get_semgrep_scan_args( raise McpError( ErrorData( code=INVALID_PARAMS, - message=("SEMGREP_API_TOKEN environment variable " - "must be set to use this tool.") - "Create a token at semgrep.dev to continue.", + message="SEMGREP_API_TOKEN environment variable " + "must be set to use this tool. Create a " + "token at semgrep.dev to continue.", ) ) args.append("--supply-chain") @@ -314,9 +314,9 @@ def get_semgrep_scan_args( raise McpError( ErrorData( code=INVALID_PARAMS, - message=("SEMGREP_API_TOKEN environment variable " - "must be set to use this tool.") - "Create a token at semgrep.dev to continue.", + message="SEMGREP_API_TOKEN environment variable " + "must be set to use this tool. Create a " + "token at semgrep.dev to continue.", ) ) args.append("--secrets")