SCA-Triage MCP Server
# SCA-Triage MCP Server
Мощный MCP-сервер (Model Context Protocol) для ИИ-ассистентов (Cline, Claude
Desktop, Cursor и др.), выполняющий **глубокий аудит безопасности Java/Spring
проектов** с помощью утилиты `ripgrep` (`rg`).
Сервер предоставляет три инструмента, которые позволяют ИИ находить опасные
sink-методы, инвентаризировать зависимости и оценивать реальную
эксплуатируемость уязвимых компонентов — не перегружая контекст.
---
## Возможности (Tools)
### 1. `search_multi_patterns` — многоуровневый поиск
Ищет список конкретных строк/методов/регулярок **или** готовый профиль
уязвимостей (например, `deserialization`) за **один эффективный проход** через
`ripgrep` (множественные `-e`). Результаты группируются по паттерну и файлу с
номерами строк и фрагментами кода.
* Аргументы:
* `patterns` (`list[str]`, опционально) — конкретные строки, методы, регурярки.
* `profile` (`string`, опционально) — профиль безопасности (см. ниже).
* `path` (`string`, опционально, по умолчанию `.`) — поддиректория для сужения.
* `max_matches` (`int`, по умолчанию `500`) — лимит суммарных совпадений.
### 2. `analyze_project_structure` — обзор проекта
Находит и разбирает `pom.xml` / `build.gradle(.kts)`, извлекает версии **Java**,
**Spring Boot**, **Spring Framework**, ключевые зависимости (со scope и версией)
и конфигурационные файлы (`application.yml`, `application.properties`).
* Аргументы: `project_root` (`string`).
### 3. `analyze_vulnerability_usage` — аудит применимости
Проверяет **реальную затронутость** проекта: ищет импорты/вхождения уязвимых
компонентов и группирует их по архитектурным слоям (Controller, Service,
Repository, Test и т.д.), помечая вхождения в контроллеры как
`[HIGH]` (потенциально доступные извне).
* Аргументы:
* `components` (`list[str]` или `string`) — FQCN или ключевые слова.
* `project_root` (`string`, опционально, по умолчанию `.`).
* `max_matches` (`int`, опционально).
* **Отсеивание ложных срабатываний.** Если установлен `ast-grep`, совпадения,
найденные ripgrep внутри комментариев/строковых литералов, отбрасываются
перед финальной категоризацией, что повышает точность триажа.
---
## Профили безопасности (для `search_multi_patterns`)
| Профиль | Что ищет |
|---|---|
| `deserialization` | `readObject`, `XMLDecoder`, `XStream.fromXML`, `enableDefaultTyping`, `Hessian`, `Kryo`, `SnakeYAML`, `convertValue` и др. |
| `sqli` | `createQuery`, `JdbcTemplate`, `prepareStatement`, `EntityManager`, `@Query`, LDAP/XPath/SpEL sinks |
| `command-execution` | `Runtime.exec`, `ProcessBuilder` |
| `path-traversal` | `Paths.get`, `FileInputStream`, `ZipEntry`, `transferTo` (zip-slip) |
| `xxe` | `DocumentBuilderFactory`, `SAXParserFactory`, `XMLInputFactory`, `resolveEntity` |
| `ssti` | `Velocity`, `FreeMarker`, `Thymeleaf`, `Mustache` |
| `ssrf` | `RestTemplate`, `WebClient`, `HttpURLConnection`, `openConnection` |
| `jndi-rmi` | `InitialContext`, `lookup(`, `ldap://`, `rmi://` (log4shell family) |
| `reflection` | `Class.forName`, `invoke(`, `sun.misc.Unsafe` |
| `logging-injection` | `LoggerFactory`, `.info(`, `JNDI` lookups |
| `spring-security-config` | `SecurityFilterChain`, `permitAll`, `csrf().disable`, `@PreAuthorize` |
| `insecure-config` | `management.endpoints.web.exposure.include`, `h2.console.enabled`, `spring.jackson.default-typing` |
| `all` | Объединение всех профилей (широкий скан) |
Профили можно комбинировать с явным списком `patterns` — они объединяются и
дедуплицируются.
---
## Установка
### 1. Установите утилиту `ripgrep`
| ОС | Команда |
|---|---|
| macOS (Homebrew) | `brew install ripgrep` |
| Debian / Ubuntu / Kali | `sudo apt install ripgrep` |
| Fedora | `sudo dnf install ripgrep` |
| Arch | `sudo pacman -S ripgrep` |
| Windows (Chocolatey) | `choco install ripgrep` |
Проверка:
```bash
rg --version # e.g. ripgrep 15.2.0
```
### 2. (Опционально) Установите `ast-grep` для отсеивания ложных срабатываний
`ast-grep` (бинарник `sg`) используется в `analyze_vulnerability_usage` для
отбрасывания совпадений, найденных ripgrep внутри **комментариев и строковых
литералов** — это снижает число ложных срабатываний. Это **опциональный**
бинарник, который ставится так же, как `ripgrep`. Без него сервер работает
как раньше, полагаясь только на ripgrep.
| ОС / менеджер | Команда |
|---|---|
| macOS (Homebrew) | `brew install ast-grep` |
| Linux (cargo) | `cargo install ast-grep --locked` |
| Linux / Windows / macOS (npm) | `npm i -g @ast-grep/cli` |
| Nix | `nix-shell -p ast-grep` |
| Скачать бинарник вручную | см. [GitHub Releases](https://github.com/ast-grep/ast-grep/releases) |
Проверка:
```bash
ast-grep --version # или: sg --version
```
> **Важно (Linux).** В Linux команда `sg` уже занята системной утилитой
> `setgroups` из пакета `util-linux` (`/usr/bin/sg`). Поэтому на Linux
> рекомендуется использовать полное имя `ast-grep`, либо убедиться, что
> каталог с ast-grep-бинарником (например `~/.cargo/bin`) идёт **раньше**
> `/usr/bin` в `PATH`. Сервер умеет распознавать системный `sg` и в этом
> случае корректно откатывается к ripgrep. В Docker-образе ast-grep кладётся
> в `/usr/local/bin` (перекрывает `/usr/bin/sg`).
### 3. Установите Python-зависимости
Требуется Python 3.10+.
```bash
cd sca-triage-mcp
# (рекомендуется) изолированное окружение
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt # или: pip install mcp
```
**Важно.** На некоторых дистрибутивах (Kali, Debian 12+) системный Python
защищён PEP 668. Используйте `venv` (как выше) или флаг
`--break-system-packages`.
### 3. Проверка работы сервера
```bash
python server.py # запуск в режиме stdio (MCP-клиенты подключаются сами)
```
## Open WebUI (нативный MCP через HTTP)
Начиная с MCP SDK 2.x сервер поддерживает **нативный** HTTP-транспорт
(Streamable HTTP) прямо из `server.py` — отдельный REST-мост больше не нужен.
Open WebUI подключается как к обычному MCP-серверу по HTTP.
### Streamable HTTP (рекомендуется)
```bash
python server.py --transport streamable-http --port 8000
# слушает на http://127.0.0.1:8000, endpoint: /mcp
```
Для доступа извне (например, если Open WebUI запущен в Docker):
```bash
python server.py --transport streamable-http --host 0.0.0.0 --port 8000
```
В Open WebUI добавьте сервер (User settings → Tools, или раздел MCP-серверов
конфигурации) с **URL** `http://<host>:8000/mcp` (тип — MCP поверх HTTP/SSE).
Поддерживаются как Streamable HTTP (`/mcp`), так и legacy SSE.
Дополнительные флаги:
| Флаг | Назначение |
|---|---|
| `--transport {stdio,sse,streamable-http}` | транспорт (по умолчанию `stdio`) |
| `--host` | адрес для HTTP-транспортов (по умолчанию `127.0.0.1`) |
| `--port` | порт (по умолчанию `8000`) |
| `--streamable-http-path` | путь endpoint'а (по умолчанию `/mcp`) |
| `--json-response` | отвечать JSON вместо SSE (без request back-channel) |
| `--stateless-http` | отключить управление сессиями |
### SSE (legacy)
```bash
python server.py --transport sse --port 8000
# endpoint: /sse (сообщения — /messages/)
```
### Проверка вручную
```bash
curl -X POST http://127.0.0.1:8000/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}'
```
Ответ содержит `mcp-session-id`, который нужно передавать в заголовке
`mcp-session-id` для последующих запросов (`tools/list`, `tools/call`).
> **Замечание о `webui_proxy.py`.** Скрипт `webui_proxy.py` (чистый REST-мост на
> stdlib + OpenAPI-схема) остался в репозитории как альтернатива для сред, где
> нужен именно HTTP/REST без SSE. При использовании нативного транспорта он не
> требуется.
> **Безопасность.** HTTP-транспорт не выполняет аутентификации и открывает аудит
> файловой системы сервера. Запускайте его на локальном хосте (`127.0.0.1`) либо
> за обратным прокси с авторизацией.
### Запуск через Docker Compose
Рецепт «под ключ» для Open WebUI — `docker-compose.yml` поднимает наш сервер в
режиме `streamable-http` и (опционально) сам Open WebUI в общей docker-сети.
```bash
docker compose up -d --build
```
| Сервис | Что делает |
|---|---|
| `sca-triage` | наш MCP-сервер (Streamable HTTP, `0.0.0.0:8000`, путь `/mcp`) |
| `open-webui` | UI на `http://localhost:3000` (опционально) |
Проекты монтируются из хостового каталога `${SCA_PROJECTS_DIR:-~/projects}`
в `/projects:ro` внутри контейнера. В запросах передавайте
`project_root="/projects/<имя-подкаталога>"`.
Подключение в Open WebUI:
* Тип — **MCP (Streamable HTTP)**.
* URL — `http://sca-triage:8000/mcp` (по имени сервиса внутри docker-сети).
* Если пробросили порт на хост — `http://localhost:8000/mcp`.
Параметры запуска задаются переменными окружения: `SCA_TRANSPORT`,
`SCA_HOST`, `SCA_PORT`, `SCA_MCP_PATH` (алиас `SCA_STREAMABLE_HTTP_PATH`).
## Настройка в VS Code + Cline
1. В Cline нажмите кнопку **MCP Servers** в правом верхнем углу и добавьте
новый сервер, либо отредактируйте файл конфигурации вручную.
Файл **`cline_mcp_settings.json`** обычно лежит в одном из мест:
* `~/.cline/cline_mcp_settings.json`
* `~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json`
2. Добавьте следующую секцию (укажите **абсолютные пути**):
```json
{
"mcpServers": {
"sca-triage": {
"command": "/absolute/path/to/sca-triage-mcp/.venv/bin/python",
"args": [
"/absolute/path/to/sca-triage-mcp/server.py"
],
"env": {},
"disabled": false,
"alwaysAllow": [
"search_multi_patterns",
"analyze_project_structure",
"analyze_vulnerability_usage"
]
}
}
}
```
> **Windows** — используйте путь к `python.exe` внутри `venv`:
> `C:\\path\\to\\sca-triage-mcp\\.venv\\Scripts\\python.exe`
3. Перезапустите Cline / переподключите сервер. В списке инструментов должны
появиться `search_multi_patterns`, `analyze_project_structure` и
`analyze_vulnerability_usage`.
---
## Примеры запросов для комплексного аудита
### Проверка на десериализацию
```
Просканируй проект в /home/user/my-api на уязвимости десериализации
(профиль deserialization) и покажи все опасные sink-методы.
```
```text
search_multi_patterns(profile="deserialization", path="/home/user/my-api")
```
### Обзор зависимостей и версий
```
Проанализируй структуру проекта /home/user/my-api: версии Java, Spring Boot,
ключевые зависимости и конфиги.
```
```text
analyze_project_structure(project_root="/home/user/my-api")
```
### Аудит применимости уязвимого компонента
```
Проверь, реально ли используется XStream (CVE-2021-21341) в проекте, и насколько
он доступен извне.
```
```text
analyze_vulnerability_usage(
components=["com.thoughtworks.xstream.XStream"],
project_root="/home/user/my-api"
)
```
Результат покажет, в каких слоях встречается компонент, и пометит `[HIGH]`,
если он используется в `Controller`/`Web`/`REST` слоях (доступен извне), или
`[LOW]` — если только внутри служб/тестов.
### Поиск по списку конкретных методов
```
Найди вхождения Runtime.getRuntime().exec, ProcessBuilder и Class.forName.
```
```text
search_multi_patterns(
patterns=["Runtime.getRuntime().exec", "ProcessBuilder", "Class.forName"],
path="/home/user/my-api"
)
```
---
## Структура файлов
```
sca-triage-mcp/
├── server.py # главный MCP-сервер (3 инструмента)
├── profiles.py # профили и наборы паттернов уязвимостей
├── rg_runner.py # обёртка над ripgrep (subprocess + парсинг --json)
├── project_analyzer.py # разбор pom.xml / build.gradle и конфигов
├── webui_proxy.py # HTTP/REST мост для Open WebUI (без зависимостей)
├── requirements.txt # зависимости (mcp)
├── pyproject.toml # метаданные пакета
├── cline_mcp_settings.example.json # пример конфигурации для Cline
└── README.md # эта документация
```
---
## Как это устроено
* **Один проход `rg`.** Все паттерны передаются в один вызов `ripgrep` через
несколько `-e` (для литералов — `--fixed-strings`, для регулярных — обычный
режим). Это в разы быстрее, чем последовательные запуски.
* **Машиночитаемый вывод.** Используется `rg --json` с парсингом событий
`match`, поэтому не нужно разбирать хрупкий текстовый вывод.
* **Игнорирование служебных каталогов.** `target/`, `build/`, `.gradle/`,
`.mvn/`, `.idea/`, `bin/`, `.git/`, `node_modules/`, а также бинарные
артефакты (`*.class`, `*.jar`, `*.zip`, …) исключаются из поиска.
* **Компактный вывод.** Результаты группируются по паттерну → файлу → строке
(с лимитами `max_matches` и обрезкой длинных строк), чтобы не перегружать
контекст ИИ.
* **Понятные ошибки.** При отсутствии `rg` сервер возвращает инструкцию по
установке; неверный профиль/путь — внятное сообщение с перечнем доступных
профилей.
* **Отсеивание ложных срабатываний через `ast-grep`.** Используется в
`analyze_vulnerability_usage`: для каждого файла, где ripgrep нашёл вхождение,
дополнительно запускается `sg --lang java --pattern ... --json` (строго
файл-за-файлом, с таймаутом 2 с) и совпадения внутри комментариев/строковых
литералов отбрасываются. Если `ast-grep` недоступен или превысил таймаут,
сервер **корректно откатывается** к ripgrep (без падений).
* **Классификация слоёв по коду.** Слой файла определяется не только по пути, но
и по содержимому: если файл содержит Spring-аннотации веб-слоя
(`@RestController`, `@Controller`, `@RequestMapping`, `@GetMapping`,
`@PostMapping`, `@PutMapping`, `@DeleteMapping`, а также Spring Security
`@PreAuthorize`/`@Secured`/`@PostAuthorize` и GraphQL/WebFlux
`@QueryMapping`/`@SchemaMapping`), он принудительно относится к
`controller` и получает флаг `[HIGH]` — даже если в пути нет слова `controller`
(например, корневой `App.java`). Файлы читаются безопасно (`utf-8`,
`errors="replace"`, лимит размера) с LRU-кэшем по `(путь, mtime, размер)`.
---
## Лицензия / предупреждение
Инструмент предназначен для легитимного аудита безопасности собственных или
авторизованных проектов. Использование для несанкционированного тестирования
запрещено и регулируется применимым законодательством.
TDQS
Scored across 3 tools
Each tool has a distinct role: raw pattern search, project metadata extraction, and vulnerability-usage assessment. There is mild overlap between search_multi_patterns and analyze_vulnerability_usage, since the latter performs import/usage searches internally, but the descriptions make the boundary clear (generic grep vs. component-level exploitability triage).
All three names follow a consistent snake_case verb_noun pattern (search_multi_patterns, analyze_project_structure, analyze_vulnerability_usage). Two share the 'analyze_' prefix on distinct objects, which reads predictably.
Three well-scoped, non-trivial tools fit a focused SCA triage workflow without bloat. It is on the lean side, but each tool earns its place rather than being a thin single-purpose wrapper.
The surface covers search, build-file/dependency discovery, and usage-based exploitability assessment, but there is no way to match discovered dependencies against a vulnerability database/CVE feed, nor to emit a structured triage report or read an arbitrary file. An agent would hit dead ends when the actual CVE-to-dependency correlation is needed.