Skip to main content
Glama
README.md
# 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

A3.6/5.0

Scored across 3 tools

Disambiguation4/5

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).

Naming Consistency5/5

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.

Tool Count4/5

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.

Completeness3/5

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.

Maintenance

ActivityMaintained
ResponsivenessNo issues