SNAP MCP Server
by MnkyBr8n
README.md
# SNAP — MCP Server
**S**napshot **N**otebook **A**bide **P**ersistence
> Code analysis pipeline exposing snapshot types via Model Context Protocol (MCP). Parses code, documents, data, and config files into structured DB snapshots for targeted AI retrieval.
---
## Table of Contents
- [Quick Start](#quick-start)
- [Agent & Client Setup](agent_setups.md)
- [LLM Permission Model](#llm-permission-model)
- [Agent Workflow](#agent-workflow)
- [Binary File Headers](#binary-file-headers)
- [Nim Parser](#nim-parser)
- [Admin CLI](#admin-cli)
- [Available MCP Tools](#available-mcp-tools)
- [Snapshot Types](#snapshot-types)
- [Storage Architecture](#storage-architecture)
- [Configuration](#configuration)
- [Logging](#logging)
- [Architecture](#architecture)
- [Security](#security)
- [Requirements](#requirements)
- [Troubleshooting](#troubleshooting)
---
## Quick Start
SNAP is distributed as a self-contained binary — no Python installation required.
---
### Binary Install
#### 1. Download the Binary
Download the binary for your platform from the [latest release](../../releases/latest):
| Platform | Binary |
| -------- | ------ |
| Windows (x86-64) | `snap-mcp.exe` |
| Linux (x86-64) | `snap-mcp` |
| macOS (arm64) | `snap-mcp` |
Place the binary in a directory of your choice, e.g. `C:\Users\<username>\snap\`.
On Linux/macOS, make it executable:
```bash
chmod +x snap-mcp
```
All parsers (Nim, tree-sitter, semgrep) are bundled — no additional installs required.
#### 2. Create the Data Directory Structure
```bash
mkdir -p data/logs data/staging data/repos data/projects
```
#### 3. Configure Environment
Create a `.env` file in the same directory as the binary:
```env
# SQLite is the default — no additional setup required
SNAP_DB_MODE=sqlite
SNAP_SQLITE_PATH=data/snap.db
# Optional: PostgreSQL
# SNAP_DB_MODE=postgres
# SNAP_POSTGRES_DSN=postgresql://user:pass@localhost:5432/snap
# Logging
SNAP_LOG_LEVEL=INFO
SNAP_LOG_JSON=true
```
#### 4. Verify
```bash
# Windows
snap-mcp.exe --help
# Linux / macOS
./snap-mcp --help
```
---
### Enterprise / Source Access
Enterprise licensing and source access inquiries: **[cll.automata@outlook.com](mailto:cll.automata@outlook.com)**
---
## Agent & Client Setup
See **[agent_setups.md](agent_setups.md)** for setup guides covering Claude Code, Claude Desktop, GitHub Copilot Chat, HTTP+SSE, and Azure cloud deployment.
---
## LLM Permission Model
The LLM has strictly limited rights enforced at runtime in `app/mcp/tools.py` — not by convention or docstrings.
### Allowed — No Approval Needed
DB snapshot reads only. The LLM never reads raw files.
| Tool | Notes |
| ---- | ----- |
| `get_project_manifest` | Read processing stats from DB |
| `query_snapshots` | Query DB by type or file path |
| `get_system_metrics` | Read system-wide aggregated metrics |
| `list_projects` | List all projects in DB |
| `list_runs` | List processing runs for a project |
### Requires Explicit User Approval Per Call
| Tool | Notes |
| ---- | ----- |
| `get_project_notebook` | Read assembled project snapshots from DB |
| `clone_to_repos` | Clones GitHub repo into repos/ — auto-ingests in background, LLM does not read files |
| `copy_to_staging` | Copies local dir to staging/ — auto-ingests in background, LLM does not read files |
| `upload_to_staging` | Upload file content to staging |
| `get_staging_info` | File names, sizes, timestamps only — no file content |
| `clear_staging` | Delete staging files for a project |
| `kill_task` | Cancel a stuck async tool call |
### Not Allowed — Raises Immediately
| Tool | Reason |
| ---- | ------ |
| `delete_project` | No delete rights |
| `promote_run` | No write rights |
| `process_local_project` | No ingest rights |
### Not Allowed Actions
The LLM never: reads raw files, reads GitHub raw content, ingests files, sorts/filters files, or processes files. SNAP does all of this.
---
## Agent Workflow
SNAP is the ingest engine. The LLM stages content — SNAP ingests it.
### GitHub Repository
```text
LLM: clone_to_repos(repo_url, vendor_id)
└─► Clones into repos/{project_id}/. project_id = repo name, derived by SNAP.
SNAP: auto-ingests in background thread → stores in DB → clears repos/
LLM (on request): query_snapshots / get_project_notebook
```
### Local Project
```text
LLM: copy_to_staging(project_id, source_path)
└─► Copies files to staging/{project_id}/. Returns immediately.
SNAP: auto-ingests in background thread → stores in DB → clears staging/
LLM (on request): query_snapshots / get_project_notebook
```
**Rules:**
- LLM stages ONE operation: clone trigger (GitHub) or staging copy (local)
- LLM does NOT ingest, filter, read, or process files — ever
- All filtering and ingest happens inside SNAP
- LLM reads only structured snapshot data from DB
---
## Binary File Headers
SNAP uses binary file headers to associate files with projects without requiring directory structure.
### Header Format
```text
FileHeader (variable size):
magic: "SNAPFILE" (8 bytes)
version: uint16 (2 bytes)
project_id_len: uint16 (2 bytes)
project_id: utf-8 string (variable)
snapshot_count: uint32 (4 bytes)
[file content follows]
```
### Usage
```python
from app.extraction.binary_packer import write_file_header, read_project_id_from_file
# Write file with project association
content = b"# Project Notes\n\nImplementation details..."
write_file_header("notes.md", "SNAP", content)
# Read project_id from file
project_id = read_project_id_from_file("notes.md") # Returns "SNAP"
```
### Auto-Ingest Workflow
```text
1. File with binary header uploaded via upload_to_staging
2. SNAP reads header → extracts project_id
3. File placed in staging/{project_id}/
4. Auto-ingested into {project_id} project in background
5. Staging cleared
```
**Use Cases:**
- Chat conversation logs (project_id = working project name)
- Project notes and documentation
- Context files for RAG queries
- Cross-project file sharing with explicit ownership
---
## Nim Parser
High-performance native parser bundled inside the snap-mcp binary. Handles all document, data, and config formats.
### Supported Formats
| Snap Type | Formats | Output Fields |
| --------- | ------- | ------------- |
| `text` (DocGraph) | `.md`, `.html`, `.htm`, `.docx`, `.pdf`, `.txt`, `.rtf` | `doc.*` |
| `csv` | `.csv`, `.tsv`, `.xml` (data) | `csv.*` |
| `config` | `.json`, `.jsonl`, `.xml` (config), `.yaml`, `.yml`, `.toml` | `config.*` |
XML is auto-classified at parse time: doc-like tags → `text`, repeated record rows → `csv`, everything else → `config`.
### Performance
| Operation | Before | Nim | Speedup |
| --------- | ------ | --- | ------- |
| Parse 1MB markdown | ~450ms | ~8ms | 56x |
| Extract CSV schema | ~180ms | ~3ms | 60x |
| Parse config JSON | ~120ms | ~4ms | 30x |
**Note:** Tree-sitter and semgrep remain in Python (external tools, already optimized).
---
## Admin CLI
Human-only operations that bypass MCP entirely. Install with `pip install -e .` then use `snap-admin`.
```bash
# List all ingested projects with snapshot and run counts
snap-admin list-projects
# Show all runs for a project (active / superseded / failed)
snap-admin runs <project_id>
# Health check and active-run summary for a project
snap-admin manifest <project_id>
# Browse snapshots — summary by type, or drill in by type or file
snap-admin snapshots <project_id>
snap-admin snapshots <project_id> --type <snapshot_type>
snap-admin snapshots <project_id> --file <source_file_path>
# Delete a project and all its data (DB, repos, staging)
snap-admin delete-project <project_id>
# Copy a local directory into staging for a project
snap-admin upload-to-staging <project_id> <source_path>
# Clone a GitHub repo directly (no LLM involved) — repos_watcher ingests
snap-admin clone-github <repo_url>
```
Also callable as `python -m app.admin <command>`.
---
## Available MCP Tools
| Tool | Permission | Description |
| ---- | ---------- | ----------- |
| `get_project_notebook` | Allowed | Read complete project snapshots from DB |
| `get_project_manifest` | Allowed | Read processing stats from DB |
| `query_snapshots` | Allowed | Query by snapshot type or file path |
| `get_system_metrics` | Allowed | System-wide aggregated metrics |
| `list_projects` | Allowed | List all projects with snapshot counts |
| `list_runs` | Allowed | List processing runs for a project |
| `clone_to_repos` | Approval required | Clone GitHub repo → auto-ingests in background |
| `copy_to_staging` | Approval required | Copy local directory into staging |
| `upload_to_staging` | Approval required | Upload file content to staging |
| `get_staging_info` | Approval required | List staging file names, sizes, timestamps |
| `clear_staging` | Approval required | Clear all staging files for a project |
| `kill_task` | Approval required | Cancel a stuck async tool call |
| `delete_project` | **Blocked** | LLM has no delete rights — use `snap-admin` |
| `promote_run` | **Blocked** | LLM has no write rights |
| `process_local_project` | **Blocked** | LLM has no ingest rights |
---
## Snapshot Types
### Code Analysis (7 types)
| Type | Parser | Description |
| ---- | ------ | ----------- |
| `file_metadata` | tree_sitter | Path, language, LOC, package info |
| `imports` | tree_sitter | External and internal module dependencies |
| `exports` | tree_sitter | Functions, classes, constants, types |
| `functions` | tree_sitter | Names, signatures, async status, decorators |
| `functions_core` | tree_sitter | Full function bodies, docstrings, return types, parameters |
| `classes` | tree_sitter | Names, inheritance, methods, properties |
| `connections` | tree_sitter | Dependencies, function calls, instantiations |
### Security & Quality (2 types)
| Type | Parser | Description |
| ---- | ------ | ----------- |
| `security` | semgrep | Vulnerabilities, secrets, SQL injection, XSS |
| `quality` | semgrep | Antipatterns, code smells, TODOs, deprecated usage |
### Documents (3 types)
| Type | Parser | Description |
| ---- | ------ | ----------- |
| `doc_metadata` | nim_parser | Title, author, date, version, language |
| `doc_content` | nim_parser | Sections, URLs, code snippets |
| `doc_analysis` | nim_parser | Requirements, entities, references, related files |
Supported: `.md`, `.html`, `.docx`, `.pdf`, `.txt`, `.rtf` — and `.xml` when classified as a document.
### CSV / Data (2 types)
| Type | Parser | Description |
| ---- | ------ | ----------- |
| `csv_schema` | nim_parser | Column names, inferred types, column count |
| `csv_data` | nim_parser | Row count, null counts, unique counts, first 5 rows |
Supported: `.csv`, `.tsv`, `.xml` (when classified as row data).
### Config (1 type)
| Type | Parser | Description |
| ---- | ------ | ----------- |
| `config_metadata` | nim_parser | Top-level keys, nested paths, env vars, DB strings, API endpoints/hosts |
Supported: `.json`, `.jsonl`, `.yaml`, `.yml`, `.toml`, `.xml` (when classified as config).
---
## Storage Architecture
SNAP uses a hybrid storage model with binary snapshot format for efficient Nim integration.
### Database Modes
| Mode | Storage | Use Case |
| ---- | ------- | -------- |
| `sqlite` | SQLite (default) | Single-user, embedded, zero-config |
| `postgres` | PostgreSQL | Multi-user, networked, production |
| `dual` | Both | Development, migration, redundancy |
Set via `.env`:
```bash
SNAP_DB_MODE=sqlite # Default
SNAP_DB_MODE=postgres # Requires SNAP_POSTGRES_DSN
SNAP_DB_MODE=dual # Both databases
```
### Binary Snapshot Format
Snapshots are stored as binary-packed data for performance and Nim compatibility.
**Snapshot Structure:**
```text
SnapshotHeader (561 bytes):
magic: "SNAP" (4 bytes)
version: uint16 (2 bytes)
snapshot_type: uint8 (1 byte)
field_count: uint16 (2 bytes)
content_hash: SHA-256 (32 bytes)
simhash: uint64 (8 bytes)
minhash: 128 × uint32 (512 bytes)
FieldDescriptor (11 bytes each):
field_id: uint16 (2 bytes)
data_type: uint8 (1 byte) # 0=string, 1=int, 2=binary, 3=array
offset: uint32 (4 bytes)
length: uint32 (4 bytes)
Data Block (variable):
Packed field data referenced by descriptors
```
**Storage:**
```sql
CREATE TABLE snapshot_notebooks (
snapshot_id TEXT PRIMARY KEY,
run_id TEXT NOT NULL,
project_id TEXT NOT NULL,
snapshot_type TEXT NOT NULL,
source_file TEXT NOT NULL,
binary_data BYTEA NOT NULL, -- Binary-packed snapshot
source_hash TEXT,
content_hash TEXT, -- SHA-256 hex
simhash BIGINT, -- 64-bit similarity hash
minhash TEXT, -- 128 × 32-bit MinHash (CSV)
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
```
### Hash-Based Versioning
| Hash Type | Size | Purpose |
| --------- | ---- | ------- |
| `source_hash` | SHA-256 | File content hash (deduplication) |
| `content_hash` | SHA-256 | Extracted content hash (change detection) |
| `simhash` | 64-bit | Similarity fingerprint (near-duplicate detection) |
| `minhash` | 128 × 32-bit | Set similarity (document comparison) |
**Versioning Logic:**
```text
New file ingested:
1. Calculate source_hash
2. Query DB for existing snapshot with same source_file + source_hash
3. If exists → skip (deduplication)
4. If not exists → create new snapshot (versioning)
5. Multiple versions coexist in DB (query by run_id or latest)
```
---
## Configuration
Environment variables use the `SNAP_` prefix.
### Database
| Variable | Default | Description |
| -------- | ------- | ----------- |
| `SNAP_DB_MODE` | `sqlite` | Database mode: `sqlite`, `postgres`, or `dual` |
| `SNAP_POSTGRES_DSN` | *(required for postgres/dual)* | PostgreSQL connection string |
| `SNAP_SQLITE_PATH` | `data/snap.db` | SQLite database path |
### Directories
| Variable | Default | Description |
| -------- | ------- | ----------- |
| `SNAP_DATA_DIR` | `data/` | Base data directory |
| `SNAP_STAGING_DIR` | `data/staging/` | File staging (auto-ingest) |
| `SNAP_REPOS_DIR` | `data/repos/` | GitHub clones (cleared after ingest) |
### System
| Variable | Default | Description |
| -------- | ------- | ----------- |
| `SNAP_LOG_LEVEL` | `INFO` | Logging level |
| `SNAP_LOG_JSON` | `true` | JSON-formatted logs |
| `SNAP_GIT_CLONE_DEPTH` | `1` | Shallow clone depth |
| `SNAP_GIT_CLONE_TIMEOUT_SECONDS` | `600` | Git clone timeout (seconds) |
### Parser Limits
| Variable | Default | Description |
| -------- | ------- | ----------- |
| `SNAP_PARSER_LIMITS_SOFT_CAP_LOC` | 1,500 | Code warning threshold (LOC) |
| `SNAP_PARSER_LIMITS_HARD_CAP_LOC` | 5,000 | Code reject threshold (LOC) |
| `SNAP_PARSER_LIMITS_SOFT_CAP_BYTES` | 500,000 | Text warning threshold (bytes) |
| `SNAP_PARSER_LIMITS_HARD_CAP_BYTES` | 10,000,000 | Text reject threshold (bytes) |
### Authentication (HTTP+SSE only, disabled by default)
| Variable | Default | Description |
| -------- | ------- | ----------- |
| `SNAP_AUTH_ENABLED` | `false` | Enable JWT/OAuth authentication |
| `SNAP_AUTH_JWT_SECRET` | *(empty)* | Secret for JWT signing |
| `SNAP_AUTH_GITHUB_CLIENT_ID` | *(empty)* | GitHub OAuth app client ID |
| `SNAP_AUTH_GITHUB_CLIENT_SECRET` | *(empty)* | GitHub OAuth app client secret |
> Stdio mode (Claude Code) is never affected by auth settings.
---
## Logging
SNAP writes structured JSON logs to three destinations simultaneously.
### Log Files
| File | Level | Rotation | Notes |
| ---- | ----- | -------- | ----- |
| `data/logs/app.log` | WARNING+ | None | Plain FileHandler — VSCode-safe, always readable |
| `data/logs/app_debug.log` | INFO+ | 5 MB × 3 | RotatingFileHandler — full debug trail |
| stderr | all levels | — | MCP-compatible; required for stdio transport |
### Log Format
Controlled by `SNAP_LOG_JSON` (default `true`). Each line is a JSON object:
```json
{"ts": "2026-02-15 12:00:00,000", "level": "INFO", "name": "snap", "msg": "Snapshot created", "snapshot_id": "...", "project_id": "...", "snapshot_type": "functions", "parser": "tree_sitter", "fields_count": 12}
```
Set `SNAP_LOG_JSON=false` for human-readable output:
```text
2026-02-15 12:00:00,000 INFO snap Snapshot created
```
### Structured Log Events
| Event | Level | Key Fields |
| ----- | ----- | ---------- |
| File parsed | DEBUG | `path`, `tag`, `size`, `language`, `parse_duration_ms`, `snapshots_created`, `parsers` |
| Snapshot created | INFO | `snapshot_id`, `snapshot_type`, `parser`, `fields_count` |
| File categorized | INFO / WARNING / ERROR | `path`, `size`, `tag`, `reason` |
| Repo processing complete | INFO | `files_processed`, `snapshots_created`, `snapshot_types_summary`, `parsers_summary`, `total_duration_ms` |
### File Tags
| Tag | Level | Meaning |
| --- | ----- | ------- |
| `normal` | INFO | Within soft cap — processed normally |
| `large` | WARNING | Exceeds `SOFT_CAP_LOC` / `SOFT_CAP_BYTES` — processed with warning |
| `potential_god` | WARNING | Suspected god file — processed with warning |
| `rejected` | ERROR | Exceeds `HARD_CAP_LOC` / `HARD_CAP_BYTES` — skipped |
---
## Architecture
### Pipeline Flow
```text
GitHub:
clone_to_repos(repo_url)
↓ clone completes synchronously
repos/{project_id}/
↓ auto-ingest background thread
ingest_cloned_repo() ← security filtering, file enumeration
↓
file_router → parsers → field_mapper → snapshot_builder → DB
↓
repos/ cleared
Local:
copy_to_staging(source_path)
↓ stage_directory() filters and copies
staging/{project_id}/
↓ auto-ingest background thread
process_project() ← security filtering, file enumeration
↓
file_router → parsers → field_mapper → snapshot_builder → DB
↓
staging/ cleared
```
### File Structure
```text
SNAP/
├── app/
│ ├── admin.py # Admin CLI (human-only: delete, upload, clone, list)
│ ├── main.py # Orchestration pipeline
│ ├── config/
│ │ └── settings.py
│ ├── extraction/
│ │ ├── binary_packer.py # Binary snapshot packer/unpacker (Nim-compatible)
│ │ ├── field_mapper.py # Maps parser output to snapshot types
│ │ └── snapshot_builder.py
│ ├── ingest/
│ │ ├── file_router.py # Routes files to parsers by extension
│ │ ├── github_cloner.py # Shallow clone → repos/
│ │ └── local_loader.py # stage_directory() + staging helpers
│ │
│ ├── logging/
│ │ └── logger.py
│ ├── mcp/
│ │ ├── auth.py # JWT + GitHub OAuth
│ │ ├── run.py # Entry point: stdio or HTTP+SSE
│ │ ├── security.py # Input validation, path traversal prevention
│ │ ├── server.py # MCP server, tool registry, Starlette app
│ │ └── tools.py # Tool handlers + permission enforcement
│ ├── parsers/
│ │ ├── nim_parser.nim # Native parser: doc, csv, config formats (compile to binary)
│ │ ├── nim_parser.py # Python wrapper for Nim parser
│ │ ├── pre_converter.nim # Pre-processing helper for Nim parser
│ │ ├── semgrep_parser.py
│ │ └── tree_sitter_parser.py
│ ├── schemas/
│ │ ├── master_notebook.yaml
│ │ └── snapshot_templates/ # JSON templates (defined and gated by master_notebook.yaml)
│ ├── security/
│ │ └── network_policy.py
│ └── storage/
│ ├── db.py
│ └── snapshot_repo.py # CRUD, upsert, run versioning
├── data/
│ ├── logs/
│ ├── projects/ # Project manifests
│ ├── repos/ # GitHub clones (cleared after ingest)
│ └── staging/ # Local file staging (cleared after ingest)
├── docker/
│ └── Dockerfile
├── docker-compose.yml
├── pyproject.toml
├── run_mcp.bat
└── run_mcp.sh
```
---
## Security
### LLM Autonomy Restrictions
- **No raw file reads** — LLM reads only structured DB snapshots
- **No ingest** — SNAP ingests and parses; LLM never touches files
- **No delete/write rights** — `delete_project`, `promote_run` raise immediately
- **project_id locked** — derived from repo URL on clone; LLM cannot supply or rename
- **vendor_id restricted** — alphanumeric + `_@.-` only, max 64 chars; blocks injection chars
- **Runtime enforcement** — `ALLOWED_TOOLS` / `NOT_ALLOWED_TOOLS` frozensets checked at handler entry
### Input Validation
- **Project ID**: `^[a-zA-Z0-9_-]{3,64}$`
- **Vendor ID**: `^[a-zA-Z0-9_@.\-]{1,64}$`
- **Filenames**: No path traversal (`..`, `\x00`, `~`), no backslash, reserved names blocked
- **Repo URLs**: HTTPS GitHub URLs only
- **Symlinks**: Rejected at staging time
### Staging Filters (`stage_directory`)
All filtering enforced by SNAP at copy time — LLM has no role.
**Pruned directories** (never traversed):
`node_modules` · `.git` · `.svn` · `.hg` · `__pycache__` · `.venv` · `venv` · `.next` · `.nuxt` · `.expo` · `.gradle` · `build` · `dist` · `target` · `Pods` · `.terraform` · `vendor`
**Ignored file patterns:**
| Category | Patterns |
| -------- | -------- |
| Secrets / credentials | `*.pem`, `*.key`, `*.p12`, `.env`, `.env.*`, `*.token`, `serviceAccountKey.json` |
| Cloud configs | `.aws/`, `.azure/`, `.gcloud/` |
| Build artifacts | `*.min.js`, `*.min.css`, `*.pyc`, `*.class`, `*.so`, `*.dll`, `*.exe` |
| Coverage / logs | `coverage/`, `*.log`, `*.lock` |
### Schema Governance
`app/schemas/master_notebook.yaml` is the single source of truth for all snapshot types and field definitions.
- **Template validation** — `SnapshotBuilder` validates every template file against the master notebook at startup. Templates not registered in `snapshot_templates` are rejected and never run.
- **Field validation** — Any field in a template not registered in `field_id_registry` causes the entire template to be rejected.
- **MCP query validation** — `validate_snapshot_type` reads valid types directly from the master notebook at runtime. No hardcoded lists.
### Parse-Time Injection Protection
- **Prompt injection** — 30+ patterns blocked: instruction overrides, role hijacking, jailbreak triggers, exfiltration probes
- **Secret redaction** — AWS keys, GitHub tokens, JWTs, API keys auto-redacted in all field values
- **AST-level filtering** — tree-sitter nodes scanned for imperative patterns; flagged as `[FILTERED:IMPERATIVE]`
- **Content safety** — high-entropy detection, base64 blocks, hex-encoded data flagged before DB insertion
---
## Requirements
The binary release has no install-time dependencies. All parsers and libraries are bundled.
| Requirement | Notes |
| ----------- | ----- |
| OS | Windows x86-64 · Linux x86-64 · macOS |
| SQLite3 | Bundled — zero config |
| PostgreSQL | 14+ — optional, only if `SNAP_DB_MODE=postgres` |
**Bundled in the binary:** tree-sitter (all languages) · semgrep · nim_parser · all Python dependencies.
---
## Troubleshooting
### MCP Server Won't Connect
1. **Logs must go to stderr** (not stdout):
```python
handler = logging.StreamHandler(sys.stderr)
```
2. **Use the wrapper script** — Claude Code does not respect cwd:
```batch
@echo off
cd /d C:\Users\<username>\snap
snap-mcp.exe %*
```
3. **Verify connection**:
```bash
claude mcp list
# snap: ... - ✓ Connected
```
### Missing postgres_dsn
```env
SNAP_POSTGRES_DSN=postgresql://user:pass@localhost:5432/snap
```
### Semgrep Not Running
SNAP auto-installs and upgrades semgrep on startup. If auto-install fails:
```bash
.venv\Scripts\python.exe -m pip install --upgrade semgrep
```
---
© CLL Automata
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues