scan_directory
Scan a directory for security vulnerabilities and code quality issues using Semgrep static analysis. Specify the absolute directory path and optionally choose a rule configuration.
Instructions
Performs a Semgrep scan on a directory
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Absolute path to the directory to scan (must be within an allowed workspace root) | |
| config | No | Semgrep configuration (e.g. "auto" or absolute path to rule file) | auto |
Implementation Reference
- src/index.ts:253-270 (schema)Input schema definition for scan_directory tool, registered in ListToolsRequestSchema handler
{ name: 'scan_directory', description: 'Performs a Semgrep scan on a directory', inputSchema: { type: 'object', properties: { path: { type: 'string', description: 'Absolute path to the directory to scan (must be within an allowed workspace root)' }, config: { type: 'string', description: 'Semgrep configuration (e.g. "auto" or absolute path to rule file)', default: 'auto' } }, required: ['path'] } - src/index.ts:375-376 (registration)Switch-case dispatch that routes scan_directory requests to handleScanDirectory
case 'scan_directory': return await this.handleScanDirectory(request.params.arguments); - src/index.ts:398-433 (handler)Core handler that validates path/config, builds semgrep args with --json output, executes semgrep scan via execFileAsync, and returns results or error
private async handleScanDirectory(args: any) { if (!args.path) { throw new McpError(ErrorCode.InvalidParams, 'Path is required'); } const scanPath = validateAbsolutePath(args.path, 'path'); const config = args.config || 'auto'; const configParam = validateAbsolutePath(config, 'config'); try { // Use execFile with arg array to prevent shell injection (CWE-78 fix) const semgrepArgs = ['scan', '--json', '--config', configParam, scanPath]; if (process.env.SEMGREP_APP_TOKEN && config.startsWith('r/')) { semgrepArgs.splice(1, 0, '--oauth-token', process.env.SEMGREP_APP_TOKEN); } const loggedArgs = semgrepArgs.map((arg, idx) => idx > 0 && semgrepArgs[idx - 1] === '--oauth-token' ? '[REDACTED]' : arg ); console.error(`Executing: semgrep ${loggedArgs.join(' ')}`); const { stdout } = await execFileAsync('semgrep', semgrepArgs, { maxBuffer: SEMGREP_MAX_BUFFER, }); return { content: [{ type: 'text', text: stdout }] }; } catch (error: any) { return { content: [{ type: 'text', text: `Error scanning: ${error.message}` }], isError: true }; } } - src/index.ts:119-159 (helper)Validates that the path/config is absolute, within allowed roots, and free of shell metacharacters; handles registry config refs (p/, r/, auto) for the config parameter
export function validateAbsolutePath(pathToValidate: string, paramName: string): string { if (paramName === 'config' && ( pathToValidate.startsWith('p/') || pathToValidate.startsWith('r/') || pathToValidate === 'auto' )) { return validateRegistryConfig(pathToValidate); } validateNoShellMetacharacters(pathToValidate, paramName); if (!path.isAbsolute(pathToValidate)) { throw new McpError( ErrorCode.InvalidParams, `${paramName} must be an absolute path. Received: ${pathToValidate}` ); } const normalizedPath = resolvePathForValidation(pathToValidate); if (!path.isAbsolute(normalizedPath)) { throw new McpError( ErrorCode.InvalidParams, `${paramName} contains invalid path traversal sequences` ); } const allowedRoots = getAllowedRoots(); const isWithinAllowedRoots = allowedRoots.some((allowedRoot) => isPathWithinRoot(allowedRoot, normalizedPath) ); if (!isWithinAllowedRoots) { throw new McpError( ErrorCode.InvalidParams, `${paramName} must be within an allowed workspace root (${formatAllowedRoots(allowedRoots)})` ); } return normalizedPath; }