# Laraguard MCP image > **A security audit MCP server for Laravel projects β€” built with TypeScript and stdio transport.** [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE) [![Node.js](https://img.shields.io/badge/Node.js-20%2B-green.svg)](https://nodejs.org/) [![TypeScript](https://img.shields.io/badge/TypeScript-5.x-3178C6.svg)](https://www.typescriptlang.org/) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-%40modelcontextprotocol%2Fsdk-orange)](https://github.com/modelcontextprotocol/sdk) [![Version](https://img.shields.io/badge/version-3.0.0-blueviolet.svg)](./package.json) --- ## Overview **Laraguard MCP** is a standalone [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that performs security audits on Laravel projects. It is implemented in pure TypeScript using the official `@modelcontextprotocol/sdk` and communicates over **stdio**, making it natively compatible with any MCP-capable IDE or client (Cursor, Claude Desktop, VS Code MCP extensions, etc.). The server analyses a Laravel project as an **external target** β€” it does not require Laravel to be running. It returns structured JSON findings categorised by severity, covering configuration issues, risky code patterns, and dependency hygiene. --- ## Features - πŸ” **Static code scanning** β€” 15+ rules covering SQL injection, RCE, hardcoded credentials, weak crypto, mass assignment, and LFI - 🎭 **Blade XSS scanner** β€” detects unescaped `{!! !!}` output and raw input rendering in templates - πŸ›£οΈ **Route & middleware audit** β€” flags admin routes without auth, API routes without auth:sanctum, login routes without throttle, and CSRF exceptions - πŸ“¦ **Dependency CVE feed** β€” queries the [OSV.dev](https://osv.dev/) API for real CVEs across all `composer.lock` packages - βš™οΈ **Configuration audit** β€” inspects `.env` (DEBUG, APP_KEY, APP_ENV, secure cookies) and `config/cors.php` - πŸ—‚οΈ **Project metadata** β€” reads `composer.json` to identify Laravel and PHP version constraints - πŸ’₯ **Active attack simulation** β€” fires HTTP probes (SQL injection, XSS, CSRF, auth bypass, rate limiting) against a running app - πŸ”’ **Path traversal prevention** β€” strict allowlist enforcement for all file operations - βœ‚οΈ **Secret redaction** β€” sensitive values are masked in textual output before reaching the MCP client - πŸš€ **stdio transport** β€” zero-config network; works inside any IDE that supports MCP --- ## MCP Tools The server exposes **8 tools**. All static tools accept a single `path` parameter. `attack_simulate` additionally requires a `baseUrl`. | Tool | Input | Description | |------|-------|-------------| | `project_info` | `path` | Returns metadata from `composer.json`: project name, Laravel/PHP version constraints, engine info. | | `dependency_audit` | `path` | Parses `composer.lock` and queries **OSV.dev** for real CVEs with severity and fix versions. | | `config_audit` | `path` | Inspects `.env` (DEBUG, APP_KEY, APP_ENV, session cookies) and `config/cors.php` (wildcard origins). | | `code_scan` | `path` | 15+ static pattern rules across all PHP files β€” credentials, weak crypto, mass assignment, RCE, LFI, SQL injection. | | `blade_scan` | `path` | Scans `resources/views/` Blade templates for unescaped output (`{!! !!}`) and XSS-prone patterns. | | `route_audit` | `path` | Audits route files and middleware for missing auth, missing throttle, and CSRF exception wildcards. | | `attack_simulate` | `path` + `baseUrl` | Fires 6 live HTTP probes against a running app: SQL injection, XSS, CSRF, auth bypass, rate limiting, error disclosure. | | `full_audit` | `path` | Runs `dependency_audit` + `config_audit` + `code_scan` + `blade_scan` + `route_audit` in parallel and returns a consolidated report. | ### Code Scan β€” Detected Patterns | Pattern | Severity | Finding Type | |---------|----------|--------------| | `->whereRaw(` | High | `SQL_INJECTION` | | `DB::raw(` | Medium | `RAW_SQL_USAGE` | | `unserialize(` | Critical | `UNSAFE_UNSERIALIZE` | | `shell_exec(` / `exec(` / `system(` / `passthru(` | Critical | `RCE_RISK` | | `eval(` | Critical | `EVAL_USAGE` | | `password = 'literal'` | Critical | `HARDCODED_PASSWORD` | | `api_key = 'literal'` | Critical | `HARDCODED_API_KEY` | | Long hardcoded tokens/secrets | High | `HARDCODED_SECRET` | | `md5(` | High | `WEAK_HASH_MD5` | | `sha1(` | Medium | `WEAK_HASH_SHA1` | | `protected $guarded = []` | High | `MASS_ASSIGNMENT_UNGUARDED` | | `file_get_contents($request…)` | Critical | `PATH_TRAVERSAL_RISK` | | `include/require($request…)` | Critical | `LFI_RISK` | ### Audit Report Schema Every tool returns a structured JSON report: ```json { "summary": { "critical": 0, "high": 1, "medium": 2, "low": 0, "info": 1 }, "findings": [ { "severity": "high", "type": "SQL_INJECTION", "title": "Potential SQL injection via whereRaw", "file": "app/Http/Controllers/UserController.php", "line": 42, "evidence": "->whereRaw('email = ' . $email)", "recommendation": "Avoid raw SQL with user input. Use parameter binding/query builder." } ], "metadata": { "scannedPath": "/absolute/path/to/laravel-project", "engine": "Laraguard MCP", "version": "3.0.0", "timestamp": "2025-01-01T00:00:00.000Z", "durationMs": 312 } } ``` --- ## Architecture ``` src/ β”œβ”€β”€ index.ts β€” MCP server bootstrap and tool registration β”œβ”€β”€ config.ts β€” Environment variable loading and validation β”œβ”€β”€ security.ts β€” Path allowlist enforcement and secret redaction β”œβ”€β”€ files.ts β€” Safe file enumeration and reading β”œβ”€β”€ tools.ts β€” Audit tool implementations β”œβ”€β”€ reports.ts β€” Report aggregation and severity summarization └── types.ts β€” Domain types (Finding, AuditReport, Severity, etc.) ``` **Runtime stack:** | Component | Technology | |-----------|------------| | Runtime | Node.js 20+ | | Language | TypeScript 5.x | | Protocol | Model Context Protocol (MCP) | | Transport | `stdio` | | Schema validation | Zod | | MCP SDK | `@modelcontextprotocol/sdk` | --- ## Requirements - **Node.js** 20 or higher - **npm** 10 or higher Verify your environment: ```bash node -v npm -v ``` --- ## Installation Clone the repository and install dependencies: ```bash git clone https://github.com/ecr17dev/Laraguard-MCP.git cd "Laraguard MCP" npm install ``` --- ## Configuration Copy the example environment file and customise it: ```bash cp .env.example .env ``` ### Environment Variables | Variable | Default | Description | |----------|---------|-------------| | `MCP_BASE_PATH` | β€” | Single allowed root path for project scanning. | | `MCP_BASE_PATHS` | β€” | Comma-separated list of allowed root paths. **Takes precedence** over `MCP_BASE_PATH`. | | `MCP_MAX_FILES` | `5000` | Maximum number of files to enumerate per scan. | | `MCP_MAX_FILE_SIZE_BYTES` | `300000` | Maximum file size (in bytes) to read per file. | | `MCP_TIMEOUT_SECONDS` | `30` | Logical timeout for audit operations. | > **Priority order:** `MCP_BASE_PATHS` β†’ `MCP_BASE_PATH` β†’ current working directory. ### Example `.env` ```env # Allow scanning two project roots MCP_BASE_PATHS="/Users/yourname/projects/my-laravel-app,/srv/workspaces/api" # Scan limits MCP_MAX_FILES=5000 MCP_MAX_FILE_SIZE_BYTES=300000 MCP_TIMEOUT_SECONDS=30 ``` --- ## Development ### Available Scripts | Command | Description | |---------|-------------| | `npm run dev` | Runs the MCP server directly from TypeScript source using `tsx` (recommended for development) | | `npm run build` | Compiles TypeScript to `dist/` | | `npm run start` | Runs the compiled server from `dist/index.js` | | `npm run check` | Type-checks the project without emitting output | ### Running in Development Mode ```bash npm run dev ``` ### Building for Production ```bash npm run check # Validate types first npm run build # Emit to dist/ npm run start # Run compiled output ``` --- ## Integration with MCP Clients ### Generic MCP Configuration (JSON) Add the following to your MCP client's configuration file, replacing the path with the absolute path to your installation: ```json { "mcpServers": { "laraguard": { "command": "node", "args": ["/absolute/path/to/Laraguard MCP/dist/index.js"], "env": { "MCP_BASE_PATHS": "/absolute/path/to/your-laravel-project" } } } } ``` ### Using Development Mode (tsx) If you prefer to run without building first: ```json { "mcpServers": { "laraguard": { "command": "npx", "args": ["tsx", "/absolute/path/to/Laraguard MCP/src/index.ts"], "env": { "MCP_BASE_PATHS": "/absolute/path/to/your-laravel-project" } } } } ``` ### Cursor IDE Open **Settings β†’ MCP** and paste the JSON block above. Cursor will detect the server on the next reload. ### Claude Desktop Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) and add the `laraguard` entry under `mcpServers`. --- ## Tool Usage Reference ### `project_info` ```json { "path": "/absolute/path/to/laravel-project" } ``` Returns basic project metadata without performing any security checks. Use it to confirm the target is a valid Laravel project and inspect framework and PHP version constraints before auditing. --- ### `dependency_audit` ```json { "path": "/absolute/path/to/laravel-project" } ``` Parses `composer.lock`, extracts all locked package names and versions, and queries the **[OSV.dev](https://osv.dev/) batch API** for known CVEs. Each vulnerability is returned as a finding with: - CVE/GHSA identifier and summary - Severity (mapped from CVSS score) - Affected package version and recommended fix version - Direct link to the advisory page --- ### `config_audit` ```json { "path": "/absolute/path/to/laravel-project" } ``` | Check | File | Severity | |-------|------|----------| | `APP_DEBUG=true` | `.env` | High | | `APP_ENV=local` | `.env` | Medium | | `APP_KEY=` (empty) | `.env` | Critical | | `SESSION_SECURE_COOKIE=false` | `.env` | Medium | | Wildcard CORS origin (`'*'`) | `config/cors.php` | Medium | --- ### `code_scan` ```json { "path": "/absolute/path/to/laravel-project" } ``` Performs line-by-line static analysis across all PHP files. Returns every matching finding with file path, line number, and evidence snippet. See the [Code Scan β€” Detected Patterns](#code-scan--detected-patterns) table above for the full rule set. --- ### `blade_scan` ```json { "path": "/absolute/path/to/laravel-project" } ``` Scans all `.blade.php` files under `resources/views/` for XSS-prone output patterns: | Check | Severity | |-------|----------| | `{!! $variable !!}` β€” unescaped variable | High | | `{!! request( !!}` / `{!! old( !!}` β€” raw user input | Critical | | `echo $_GET` / `echo $_POST` in blade PHP blocks | High | --- ### `route_audit` ```json { "path": "/absolute/path/to/laravel-project" } ``` Reads `routes/web.php`, `routes/api.php`, and `app/Http/Middleware/VerifyCsrfToken.php`: | Check | File | Severity | |-------|------|----------| | Admin/dashboard route without `auth` middleware | `routes/web.php` | Critical | | API route without `auth:sanctum` / `auth:api` | `routes/api.php` | High | | Login/register route without `throttle` middleware | Route files | Medium | | Wildcard pattern in `VerifyCsrfToken::$except` | `VerifyCsrfToken.php` | High | --- ### `attack_simulate` ```json { "path": "/absolute/path/to/laravel-project", "baseUrl": "http://localhost:8000" } ``` > ⚠️ **Only use against local or staging environments. Never run against production.** Fires 6 live HTTP probes against the running application: | Probe | Method & Endpoint | What it Tests | |-------|------------------|---------------| | `error_disclosure` | `GET /__invalid_route__` | Framework/stack-trace info leakage | | `sql_injection_login` | `POST /login` with SQLi payload | SQL injection in login form | | `reflected_xss` | `GET /search?q=