Help:13-alpha MCP: Difference between revisions
Mitrofanov (talk | contribs) No edit summary |
m (partial review and fixes) |
||
| Line 13: | Line 13: | ||
* Python 3.10+ | * Python 3.10+ | ||
* Доступ к Svacer | * Доступ к серверу Svacer: URL + логин/пароль | ||
=== Режим STDIO === | === Режим STDIO === | ||
Подходит для настольных клиентов: Claude Desktop, Claude Code, Cursor, VS Code. | Подходит для настольных клиентов: Claude Desktop, Claude Code, Cursor, VS Code. | ||
git clone <nowiki>https://gitlab.ispras.ru/svacerai/mcp.git</nowiki> && cd mcp | |||
python3 -m venv .venv | python3 -m venv .venv | ||
| Line 26: | Line 26: | ||
# Проверить запуск (сервер ожидает данные на stdin; для выхода — Ctrl+C) | # Проверить запуск (сервер ожидает данные на stdin; для выхода — Ctrl+C) | ||
.venv/bin/svacer-mcp | .venv/bin/svacer-mcp | ||
После <code>pip install -e .</code> в окружении становится доступна команда <code>svacer-mcp</code> — её указывают в конфигурации клиентов ниже. | После <code>pip install -e .</code> в окружении становится доступна команда <code>svacer-mcp</code> — её указывают в конфигурации клиентов ниже. | ||
| Line 33: | Line 34: | ||
'''Требования:''' Docker, Docker Compose. | '''Требования:''' Docker, Docker Compose. | ||
cp .env.example .env | |||
# В .env обязательно задать SVACER_MCP_TOKEN — без него сервер не запускается | # В .env обязательно задать SVACER_MCP_TOKEN — без него сервер не запускается | ||
| Line 41: | Line 42: | ||
# MCP endpoint: <nowiki>http://localhost:8002/mcp</nowiki> | # MCP endpoint: <nowiki>http://localhost:8002/mcp</nowiki> | ||
# Клиенты передают заголовок: Authorization: Bearer <SVACER_MCP_TOKEN> | # Клиенты передают заголовок: Authorization: Bearer <SVACER_MCP_TOKEN> | ||
Внешний порт хоста задаётся переменной <code>MCP_PORT</code> (по умолчанию <code>8002</code>), внутри контейнера сервер всегда слушает порт <code>8000</code>. | Внешний порт хоста задаётся переменной <code>MCP_PORT</code> (по умолчанию <code>8002</code>), внутри контейнера сервер всегда слушает порт <code>8000</code>. | ||
| Line 50: | Line 52: | ||
Укажите '''абсолютный путь''' к <code>svacer-mcp</code> из вашего venv (<code>which svacer-mcp</code> в активированном venv или <code>/path/to/mcp/.venv/bin/svacer-mcp</code>). | Укажите '''абсолютный путь''' к <code>svacer-mcp</code> из вашего venv (<code>which svacer-mcp</code> в активированном venv или <code>/path/to/mcp/.venv/bin/svacer-mcp</code>). | ||
{ | |||
"mcpServers": { | "mcpServers": { | ||
"svacer": { | "svacer": { | ||
| Line 61: | Line 64: | ||
} | } | ||
} | } | ||
} | } | ||
==== Claude Code ==== | ==== Claude Code ==== | ||
claude mcp add svacer \ | |||
-e SVACER_URL=<nowiki>https://your-svacer.example.com</nowiki> \ | -e SVACER_URL=<nowiki>https://your-svacer.example.com</nowiki> \ | ||
-e SVACER_LOGIN=your-login \ | -e SVACER_LOGIN=your-login \ | ||
-e SVACER_PASSWORD=your-password \ | -e SVACER_PASSWORD=your-password \ | ||
-- /path/to/mcp/.venv/bin/svacer-mcp | -- /path/to/mcp/.venv/bin/svacer-mcp | ||
==== VS Code ==== | ==== VS Code ==== | ||
Файл <code>.vscode/mcp.json</code> в корне рабочей директории: | Файл <code>.vscode/mcp.json</code> в корне рабочей директории: | ||
{ | |||
"servers": { | "servers": { | ||
"svacer": { | "svacer": { | ||
| Line 84: | Line 88: | ||
} | } | ||
} | } | ||
} | } | ||
==== Cursor ==== | ==== Cursor ==== | ||
Файл <code>.cursor/mcp.json</code> в корне проекта или глобально: | Файл <code>.cursor/mcp.json</code> в корне проекта или глобально: | ||
{ | |||
"mcpServers": { | "mcpServers": { | ||
"svacer": { | "svacer": { | ||
| Line 99: | Line 104: | ||
} | } | ||
} | } | ||
} | } | ||
==== OpenWebUI ==== | ==== OpenWebUI ==== | ||
# Развернуть через Docker (см. [[#Режим HTTP (Docker)|Режим HTTP]]). | |||
# Развернуть через Docker (см. | |||
# Открыть '''Settings → Tools''' (или '''Admin Panel → Settings → Tools'''). | # Открыть '''Settings → Tools''' (или '''Admin Panel → Settings → Tools'''). | ||
# Добавить сервер: | # Добавить сервер: | ||
| Line 118: | Line 122: | ||
!Описание | !Описание | ||
|- | |- | ||
| | |SVACER_URL | ||
| | |<nowiki>https://svacer-demo.ispras.ru</nowiki> | ||
|URL Svacer | |URL сервера Svacer | ||
|- | |- | ||
| | |SVACER_LOGIN | ||
| | |admin | ||
|Логин | |Логин | ||
|- | |- | ||
| | |SVACER_PASSWORD | ||
| | |admin | ||
|Пароль | |Пароль | ||
|- | |- | ||
| | |SVACER_TIMEOUT | ||
| | |30 | ||
|Тайм-аут HTTP-запросов к Svacer, секунды | |Тайм-аут HTTP-запросов к Svacer, секунды | ||
|- | |- | ||
| | |SVACER_TRANSPORT | ||
| | |stdio | ||
|Режим транспорта: <code>stdio</code> или <code>http</code> | |Режим транспорта: <code>stdio</code> или <code>http</code> | ||
|- | |- | ||
| | |SVACER_HTTP_PORT | ||
| | |8000 | ||
|TCP-порт сервера в режиме HTTP (внутри контейнера) | |TCP-порт сервера в режиме HTTP (внутри контейнера) | ||
|- | |- | ||
| | |SVACER_MCP_TOKEN | ||
|''(не задано)'' | |''(не задано)'' | ||
|Bearer-токен для клиентов <code>/mcp</code>. Обязателен при <code>SVACER_TRANSPORT=http</code>, в режиме STDIO игнорируется. Генерация: <code>openssl rand -hex 32</code> | |Bearer-токен для клиентов <code>/mcp</code>. Обязателен при <code>SVACER_TRANSPORT=http</code>, в режиме STDIO игнорируется. Генерация: <code>openssl rand -hex 32</code> | ||
|- | |- | ||
| | |SVACER_MCP_RESOURCE_URL | ||
| | |<nowiki>http://localhost</nowiki>:<HTTP_PORT> | ||
|Публичный URL MCP-сервера для заголовка <code>WWW-Authenticate</code> (<nowiki>RFC 9728</nowiki>). Задаётся при работе за обратным прокси | |Публичный URL MCP-сервера для заголовка <code>WWW-Authenticate</code> (<nowiki>RFC 9728</nowiki>). Задаётся при работе за обратным прокси | ||
|- | |- | ||
| | |SVACER_TOOLS | ||
|''(не задано)'' | |''(не задано)'' | ||
|Список инструментов через запятую. Если не задано, регистрируются все 8 | |Список инструментов через запятую. Если не задано, регистрируются все 8 | ||
|- | |- | ||
| | |MCP_PORT | ||
| | |8002 | ||
|Внешний порт хоста при запуске через <code>docker compose</code> (отображается на внутренний <code>SVACER_HTTP_PORT</code>) | |Внешний порт хоста при запуске через <code>docker compose</code> (отображается на внутренний <code>SVACER_HTTP_PORT</code>) | ||
|} | |} | ||
| Line 162: | Line 166: | ||
==== Ограничение набора инструментов ==== | ==== Ограничение набора инструментов ==== | ||
Чтобы запустить сервер с подмножеством инструментов (например, для уменьшения объёма контекста у модели или разграничения доступа), задайте <code>SVACER_TOOLS</code>: | Чтобы запустить сервер с подмножеством инструментов (например, для уменьшения объёма контекста у модели или разграничения доступа), задайте <code>SVACER_TOOLS</code>: | ||
SVACER_TOOLS=get_projects,get_snapshots,get_markers | |||
Допустимые имена: <code>get_projects</code>, <code>get_snapshots</code>, <code>get_warnings</code>, <code>get_markers</code>, <code>get_project_stats</code>, <code>get_project_groups</code>, <code>get_advanced_file_preview</code>, <code>get_diff</code>. Неизвестное имя в списке приводит к ошибке при запуске. Если переменная пустая или не задана, регистрируются все 8 инструментов. | Допустимые имена: <code>get_projects</code>, <code>get_snapshots</code>, <code>get_warnings</code>, <code>get_markers</code>, <code>get_project_stats</code>, <code>get_project_groups</code>, <code>get_advanced_file_preview</code>, <code>get_diff</code>. Неизвестное имя в списке приводит к ошибке при запуске. Если переменная пустая или не задана, регистрируются все 8 инструментов. | ||
| Line 181: | Line 185: | ||
==== Передача токена клиентом ==== | ==== Передача токена клиентом ==== | ||
Большинство HTTP-клиентов MCP (OpenWebUI и др.) позволяют задать произвольный заголовок <code>Authorization</code> в настройках инструмента — указывается значение <code>Bearer <токен></code>. Для ручной проверки: | Большинство HTTP-клиентов MCP (OpenWebUI и др.) позволяют задать произвольный заголовок <code>Authorization</code> в настройках инструмента — указывается значение <code>Bearer <токен></code>. Для ручной проверки: | ||
curl -H "Authorization: Bearer $SVACER_MCP_TOKEN" \ | |||
<nowiki> </nowiki> -H 'Content-Type: application/json' \ | <nowiki> </nowiki> -H 'Content-Type: application/json' \ | ||
<nowiki> </nowiki> -H 'Accept: application/json, text/event-stream' \ | <nowiki> </nowiki> -H 'Accept: application/json, text/event-stream' \ | ||
<nowiki> </nowiki> -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}' \ | <nowiki> </nowiki> -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}' \ | ||
<nowiki> </nowiki> <nowiki>http://localhost:8002/mcp</nowiki | <nowiki> </nowiki> <nowiki>http://localhost:8002/mcp</nowiki> | ||
== Инструменты == | == Инструменты == | ||
| Line 193: | Line 197: | ||
!Назначение | !Назначение | ||
|- | |- | ||
| | |get_projects | ||
|Список проектов с ветками — точка входа | |Список проектов с ветками — точка входа | ||
|- | |- | ||
| | |get_snapshots | ||
|Снимки конкретной ветки, от нового к старому | |Снимки конкретной ветки, от нового к старому | ||
|- | |- | ||
| | |get_project_stats | ||
|Агрегированные метрики снимка: severity / review / checker | |Агрегированные метрики снимка: severity / review / checker | ||
|- | |- | ||
| | |get_markers | ||
|Компактный список маркеров с серверной фильтрацией | |Компактный список маркеров с серверной фильтрацией | ||
|- | |- | ||
| | |get_warnings | ||
|Полные предупреждения с трассами и историей | |Полные предупреждения с трассами и историей разметки | ||
|- | |- | ||
| | |get_diff | ||
|Сравнение двух снимков: new / missing / modified / matched | |Сравнение двух снимков: new / missing / modified / matched | ||
|- | |- | ||
| | |get_advanced_file_preview | ||
|Фрагмент исходного кода вокруг строки | |Фрагмент исходного кода вокруг строки | ||
|- | |- | ||
| | |get_project_groups | ||
|Группа проектов по имени или UUID | |Группа проектов по имени или UUID | ||
|} | |} | ||
| Line 224: | Line 228: | ||
'''Вызов:''' | '''Вызов:''' | ||
get_projects() | |||
'''Ответ:''' | '''Ответ:''' | ||
[ | |||
{ | { | ||
"project_id": "91630e84-db2f-4d8c-8716-68b7fdf17a66", | "project_id": "91630e84-db2f-4d8c-8716-68b7fdf17a66", | ||
| Line 240: | Line 245: | ||
] | ] | ||
} | } | ||
] | ] | ||
---- | ---- | ||
| Line 253: | Line 258: | ||
!Описание | !Описание | ||
|- | |- | ||
| | |project_id | ||
|string (UUID) | |string (UUID) | ||
|да | |да | ||
|Из <code>get_projects</code> | |Из <code>get_projects</code> | ||
|- | |- | ||
| | |branch_id | ||
|string (UUID) | |string (UUID) | ||
|да | |да | ||
|Из <code>get_projects</code> | |Из <code>get_projects</code> | ||
|- | |- | ||
| | |name_filter | ||
|string | |string | ||
|нет | |нет | ||
|Подстрока или regex для фильтра по имени снимка | |Подстрока или regex для фильтра по имени снимка | ||
|} | |} | ||
'''Вызов:''' | '''Вызов:''' | ||
get_snapshots( | |||
project_id="91630e84-db2f-4d8c-8716-68b7fdf17a66", | project_id="91630e84-db2f-4d8c-8716-68b7fdf17a66", | ||
branch_id="77f66b9e-0453-4ae9-a187-88950b4c4bc4" | branch_id="77f66b9e-0453-4ae9-a187-88950b4c4bc4" | ||
) | ) | ||
'''Ответ:''' | '''Ответ:''' | ||
[ | |||
{ | { | ||
"snapshot_id": "b42cb563-86f4-4f96-900a-7782163327c9", | "snapshot_id": "b42cb563-86f4-4f96-900a-7782163327c9", | ||
| Line 283: | Line 290: | ||
"link": "<nowiki>https://svacer-demo.ispras.ru/</nowiki>..." | "link": "<nowiki>https://svacer-demo.ispras.ru/</nowiki>..." | ||
} | } | ||
] | ] | ||
---- | ---- | ||
=== get_project_stats === | === get_project_stats === | ||
Агрегированные метрики по снимку: общее количество предупреждений, распределение по критичности, по статусу | Агрегированные метрики по снимку: общее количество предупреждений, распределение по критичности, по статусу разметки, по детекторам. Наиболее быстрый способ получить общую картину по проекту. | ||
'''Параметры.''' | '''Параметры.''' | ||
| Line 296: | Line 303: | ||
!Описание | !Описание | ||
|- | |- | ||
| | |project_id | ||
|string (UUID) | |string (UUID) | ||
|да | |да | ||
| | |Из <code>get_projects</code> | ||
|- | |- | ||
| | |branch_id | ||
|string (UUID) | |string (UUID) | ||
|да | |да | ||
| | |Из <code>get_projects</code> | ||
|- | |- | ||
| | |snapshot_id | ||
|string (UUID) | |string (UUID) | ||
|да | |да | ||
| | |Из <code>get_snapshots</code> | ||
|} | |} | ||
'''Вызов:''' | '''Вызов:''' | ||
get_project_stats( | |||
project_id="91630e84-db2f-4d8c-8716-68b7fdf17a66", | project_id="91630e84-db2f-4d8c-8716-68b7fdf17a66", | ||
branch_id="77f66b9e-0453-4ae9-a187-88950b4c4bc4", | branch_id="77f66b9e-0453-4ae9-a187-88950b4c4bc4", | ||
snapshot_id="b42cb563-86f4-4f96-900a-7782163327c9" | snapshot_id="b42cb563-86f4-4f96-900a-7782163327c9" | ||
) | ) | ||
'''Ответ:''' | '''Ответ:''' | ||
{ | |||
"total_warnings": 771, | "total_warnings": 771, | ||
"by_severity": { | "by_severity": { | ||
| Line 339: | Line 348: | ||
"NULL_AFTER_DEREF": 27 | "NULL_AFTER_DEREF": 27 | ||
} | } | ||
} | } | ||
---- | ---- | ||
=== get_markers === | === get_markers === | ||
Компактный список маркеров с серверной фильтрацией. Основной инструмент для перечисления и обзора: его следует предпочитать <code>get_warnings</code>, когда не требуются развёрнутые поля — трассы и история | Компактный список маркеров с серверной фильтрацией. Основной инструмент для перечисления и обзора: его следует предпочитать <code>get_warnings</code>, когда не требуются развёрнутые поля — трассы и история разметки. | ||
По умолчанию ответ ограничен 30 маркерами и содержит компактный набор полей. Подробнее об ограничении объёма см. раздел Про объём ответа | По умолчанию ответ ограничен 30 маркерами и содержит компактный набор полей. Подробнее об ограничении объёма см. раздел [[#Про объём ответа|Про объём ответа]]. | ||
'''Параметры.''' | '''Параметры.''' | ||
| Line 354: | Line 363: | ||
!Описание | !Описание | ||
|- | |- | ||
| | |project_id | ||
|string (UUID) | |string (UUID) | ||
|да | |да | ||
| | |Из <code>get_projects</code> | ||
|- | |- | ||
| | |branch_id | ||
|string (UUID) | |string (UUID) | ||
|да | |да | ||
| | |Из <code>get_projects</code> | ||
|- | |- | ||
| | |snapshot_id | ||
|string (UUID) | |string (UUID) | ||
|да | |да | ||
| | |Из <code>get_snapshots</code> | ||
|- | |- | ||
| | |severity | ||
| | |string[] | ||
|нет | |нет | ||
|<code>Critical</code>, <code>Major</code>, <code>Minor</code>, <code>Unspecified</code>. Фильтр по <code>review.severity</code> | |<code>Critical</code>, <code>Major</code>, <code>Minor</code>, <code>Unspecified</code>. Фильтр по <code>review.severity</code> применяется на стороне коннектора | ||
|- | |- | ||
| | |review | ||
| | |string[] | ||
|нет | |нет | ||
|<code>Confirmed</code>, <code>Won't fix</code>, <code>False Positive</code>, <code>Unclear</code> | |<code>Confirmed</code>, <code>Won't fix</code>, <code>False Positive</code>, <code>Unclear</code> | ||
|- | |- | ||
| | |warnClass | ||
| | |string[] | ||
|нет | |нет | ||
|Идентификатор детектора (<code>DEREF_AFTER_NULL</code>, …) | |Идентификатор детектора (<code>DEREF_AFTER_NULL</code>, …) | ||
|- | |- | ||
| | |file | ||
| | |string[] | ||
|нет | |нет | ||
|Подстрока пути к файлу | |Подстрока пути к файлу | ||
|- | |- | ||
| | |traces | ||
| | |bool | ||
|нет | |нет | ||
|Включить трассы маркеров | |Включить трассы маркеров | ||
|- | |- | ||
| | |checker_info | ||
| | |bool | ||
|нет | |нет | ||
|Включить метаданные детектора (CWE, описание) | |Включить метаданные детектора (CWE, описание) | ||
|- | |- | ||
| | |review_history | ||
| | |bool | ||
|нет | |нет | ||
|Включить историю изменений | |Включить историю изменений разметки | ||
|- | |- | ||
| | |comment_history | ||
| | |bool | ||
|нет | |нет | ||
|Включить комментарии к маркеру | |Включить комментарии к маркеру | ||
|- | |- | ||
| | |custom_filter | ||
|string | |string | ||
|нет | |нет | ||
|Имя или идентификатор сохранённого фильтра из веб-интерфейса Svacer | |Имя или идентификатор сохранённого фильтра из веб-интерфейса Svacer | ||
|- | |- | ||
| | |limit | ||
|int | |int | ||
|нет | |нет | ||
|Максимальное количество маркеров в ответе (по умолчанию | |Максимальное количество маркеров в ответе (по умолчанию 30). Значение 0 снимает ограничение | ||
|- | |- | ||
| | |fields | ||
| | |string[] | ||
|нет | |нет | ||
|Список разрешённых полей маркера верхнего уровня. По умолчанию — компактный набор <code>id, warnClass, file, line, msg, function, review</code>. Значение <code>["*"]</code> возвращает все поля коннектора (<code>id, warnClass, file, line, msg, tool, function, mtid, review</code>, а также <code>traces</code>/<code>checkerInfo</code>/<code>review_history</code>/<code>comments</code>, если они запрошены). Допустим и произвольный список | |Список разрешённых полей маркера верхнего уровня. По умолчанию — компактный набор <code>id, warnClass, file, line, msg, function, review</code>. Значение <code>["*"]</code> возвращает все поля коннектора (<code>id, warnClass, file, line, msg, tool, function, mtid, review</code>, а также <code>traces</code>/<code>checkerInfo</code>/<code>review_history</code>/<code>comments</code>, если они запрошены). Допустим и произвольный список, например <code>["id","warnClass"]</code> | ||
|} | |} | ||
'''Вызов:''' | '''Вызов:''' | ||
get_markers( | |||
project_id="91630e84-db2f-4d8c-8716-68b7fdf17a66", | project_id="91630e84-db2f-4d8c-8716-68b7fdf17a66", | ||
branch_id="77f66b9e-0453-4ae9-a187-88950b4c4bc4", | branch_id="77f66b9e-0453-4ae9-a187-88950b4c4bc4", | ||
snapshot_id="b42cb563-86f4-4f96-900a-7782163327c9", | snapshot_id="b42cb563-86f4-4f96-900a-7782163327c9", | ||
warnClass=["PROC_USE.VULNERABLE"] | warnClass=["PROC_USE.VULNERABLE"] | ||
) | ) | ||
'''Ответ:''' | '''Ответ:''' | ||
{ | |||
"total_count": 341, | "total_count": 341, | ||
"returned_count": 30, | "returned_count": 30, | ||
| Line 448: | Line 459: | ||
} | } | ||
] | ] | ||
} | } | ||
<code>total_count</code> отражает количество маркеров, удовлетворяющих фильтру до применения ограничения; <code>returned_count</code> — количество маркеров, фактически содержащихся в <code>markers</code>. При <code>truncated: true</code> следует либо сузить фильтры (<code>severity</code>, <code>warnClass</code>, <code>file</code>), либо передать <code>limit=0</code> для получения полного списка. Поля <code>tool</code> и <code>mtid</code> возвращаются только при <code>fields=["*"]</code>. | <code>total_count</code> отражает количество маркеров, удовлетворяющих фильтру до применения ограничения; <code>returned_count</code> — количество маркеров, фактически содержащихся в <code>markers</code>. При <code>truncated: true</code> следует либо сузить фильтры (<code>severity</code>, <code>warnClass</code>, <code>file</code>), либо передать <code>limit=0</code> для получения полного списка. Поля <code>tool</code> и <code>mtid</code> возвращаются только при <code>fields=["*"]</code>. | ||
---- | ---- | ||
| Line 512: | Line 524: | ||
|<code>bool</code> | |<code>bool</code> | ||
|нет | |нет | ||
|Включить историю | |Включить историю разметки. Режим расширенных полей | ||
|- | |- | ||
|<code>comment_history</code> | |<code>comment_history</code> | ||
| Line 761: | Line 773: | ||
* Критических: 1 (Confirmed) | * Критических: 1 (Confirmed) | ||
* Major: 1 (Won't fix) | * Major: 1 (Won't fix) | ||
* Остальные: 769 (Unspecified — не | * Остальные: 769 (Unspecified — не размечались) | ||
Топ-детекторы по количеству: | Топ-детекторы по количеству: | ||
| Line 770: | Line 782: | ||
# <code>DEREF_AFTER_NULL.EX</code> — 27 | # <code>DEREF_AFTER_NULL.EX</code> — 27 | ||
# <code>NULL_AFTER_DEREF</code> — 27 | # <code>NULL_AFTER_DEREF</code> — 27 | ||
</blockquote><code>Unspecified</code> в <code>by_severity</code> — маркеры без | </blockquote><code>Unspecified</code> в <code>by_severity</code> — маркеры без ручной разметки, а не «низкий приоритет». Поле <code>by_checker</code> не сортируется, на большом снимке оно может содержать более 100 ключей — чтобы получить именно топ-N, следует явно сформулировать запрос: «топ-5 детекторов». | ||
=== Тренд по нескольким снимкам === | === Тренд по нескольким снимкам === | ||
Revision as of 15:26, 22 May 2026
Архитектура
MCP — открытый стандарт, через который LLM-клиенты (Claude Desktop, Cursor, VS Code, OpenWebUI и др.) вызывают внешние инструменты. Svacer MCP соединяет одно с другим: 8 инструментов поверх публичного REST API Svacer, которые LLM выбирает и вызывает в ответ на обычный текстовый запрос. Вместо ручной последовательности «открыть UI, найти проект, выбрать снимок, применить фильтр» достаточно сформулировать вопрос в чате, например, «сколько критических предупреждений в последнем снимке bash?», и получить ответ. Необходимые вызовы инструментов модель выполняет самостоятельно.

Поток запроса: LLM-клиент отправляет MCP-вызов через STDIO или Streamable HTTP → server.py передаёт его в выбранный инструмент из tools/ → инструмент проверяет параметры и обращается к api_client.py → клиент получает JWT от auth.py (модуль автоматически обновляет токен по истечении срока действия или при ответе 401) → запрос отправляется в Svacer REST API.
Установка
Установка Svacer MCP, подключение клиентов и конфигурация.
Требования
- Python 3.10+
- Доступ к серверу Svacer: URL + логин/пароль
Режим STDIO
Подходит для настольных клиентов: Claude Desktop, Claude Code, Cursor, VS Code.
git clone https://gitlab.ispras.ru/svacerai/mcp.git && cd mcp python3 -m venv .venv .venv/bin/pip install -e . cp .env.example .env # Отредактировать .env — указать URL и учётные данные Svacer # Проверить запуск (сервер ожидает данные на stdin; для выхода — Ctrl+C) .venv/bin/svacer-mcp
После pip install -e . в окружении становится доступна команда svacer-mcp — её указывают в конфигурации клиентов ниже.
Режим HTTP (Docker)
Подходит для веб-клиентов (OpenWebUI) и удалённого доступа.
Требования: Docker, Docker Compose.
cp .env.example .env # В .env обязательно задать SVACER_MCP_TOKEN — без него сервер не запускается echo "SVACER_MCP_TOKEN=$(openssl rand -hex 32)" >> .env docker compose up -d # MCP endpoint: http://localhost:8002/mcp # Клиенты передают заголовок: Authorization: Bearer <SVACER_MCP_TOKEN>
Внешний порт хоста задаётся переменной MCP_PORT (по умолчанию 8002), внутри контейнера сервер всегда слушает порт 8000.
Подключение клиентов
Claude Desktop
Файл конфигурации: ~/.config/Claude/claude_desktop_config.json (Linux) или %APPDATA%\Claude\claude_desktop_config.json (Windows).
Укажите абсолютный путь к svacer-mcp из вашего venv (which svacer-mcp в активированном venv или /path/to/mcp/.venv/bin/svacer-mcp).
{
"mcpServers": {
"svacer": {
"command": "/path/to/mcp/.venv/bin/svacer-mcp",
"env": {
"SVACER_URL": "https://your-svacer.example.com",
"SVACER_LOGIN": "your-login",
"SVACER_PASSWORD": "your-password"
}
}
}
}
Claude Code
claude mcp add svacer \ -e SVACER_URL=https://your-svacer.example.com \ -e SVACER_LOGIN=your-login \ -e SVACER_PASSWORD=your-password \ -- /path/to/mcp/.venv/bin/svacer-mcp
VS Code
Файл .vscode/mcp.json в корне рабочей директории:
{
"servers": {
"svacer": {
"type": "stdio",
"command": "/path/to/mcp/.venv/bin/svacer-mcp",
"env": {
"SVACER_URL": "https://your-svacer.example.com",
"SVACER_LOGIN": "your-login",
"SVACER_PASSWORD": "your-password"
}
}
}
}
Cursor
Файл .cursor/mcp.json в корне проекта или глобально:
{
"mcpServers": {
"svacer": {
"command": "/path/to/mcp/.venv/bin/svacer-mcp",
"env": {
"SVACER_URL": "https://your-svacer.example.com",
"SVACER_LOGIN": "your-login",
"SVACER_PASSWORD": "your-password"
}
}
}
}
OpenWebUI
- Развернуть через Docker (см. Режим HTTP).
- Открыть Settings → Tools (или Admin Panel → Settings → Tools).
- Добавить сервер:
http://localhost:8002/mcp— если OpenWebUI работает на хосте, снаружи Docker.http://svacer-mcp:8000/mcp— если OpenWebUI развёрнут в той же compose-сети, что иsvacer-mcp(имя берётся изdocker-compose.yml→ service name, порт 8000 — внутренний порт контейнера).
- Тип подключения: MCP (Streamable HTTP).
- В настройках инструмента указать заголовок
Authorization: Bearer <SVACER_MCP_TOKEN>(значение — то же, что в.envсервера). - Сохранить — инструменты появятся в чате.
Конфигурация
| Переменная | По умолчанию | Описание |
|---|---|---|
| SVACER_URL | https://svacer-demo.ispras.ru | URL сервера Svacer |
| SVACER_LOGIN | admin | Логин |
| SVACER_PASSWORD | admin | Пароль |
| SVACER_TIMEOUT | 30 | Тайм-аут HTTP-запросов к Svacer, секунды |
| SVACER_TRANSPORT | stdio | Режим транспорта: stdio или http
|
| SVACER_HTTP_PORT | 8000 | TCP-порт сервера в режиме HTTP (внутри контейнера) |
| SVACER_MCP_TOKEN | (не задано) | Bearer-токен для клиентов /mcp. Обязателен при SVACER_TRANSPORT=http, в режиме STDIO игнорируется. Генерация: openssl rand -hex 32
|
| SVACER_MCP_RESOURCE_URL | http://localhost:<HTTP_PORT> | Публичный URL MCP-сервера для заголовка WWW-Authenticate (RFC 9728). Задаётся при работе за обратным прокси
|
| SVACER_TOOLS | (не задано) | Список инструментов через запятую. Если не задано, регистрируются все 8 |
| MCP_PORT | 8002 | Внешний порт хоста при запуске через docker compose (отображается на внутренний SVACER_HTTP_PORT)
|
Переменные читаются из .env или из окружения. Для STDIO-клиентов их можно указать в секции env конфигурации клиента.
Ограничение набора инструментов
Чтобы запустить сервер с подмножеством инструментов (например, для уменьшения объёма контекста у модели или разграничения доступа), задайте SVACER_TOOLS:
SVACER_TOOLS=get_projects,get_snapshots,get_markers
Допустимые имена: get_projects, get_snapshots, get_warnings, get_markers, get_project_stats, get_project_groups, get_advanced_file_preview, get_diff. Неизвестное имя в списке приводит к ошибке при запуске. Если переменная пустая или не задана, регистрируются все 8 инструментов.
Несколько экземпляров сервера
Параллельный запуск нескольких MCP-серверов поддерживается без ограничений.
- В режиме STDIO каждая запись в конфигурации клиента описывает отдельный процесс — несколько подключений к разным экземплярам Svacer задаются простым перечислением.
- В режиме HTTP запускаются независимые контейнеры на разных хост-портах: например,
MCP_PORT=8002для одного экземпляра иMCP_PORT=8003для другого. Для каждого контейнера задаётся собственныйSVACER_MCP_TOKEN.
Безопасность
- STDIO: сервер не открывает сетевых портов и обменивается данными через стандартные потоки ввода/вывода процесса.
- Streamable HTTP: эндпоинт
/mcpтребует заголовокAuthorization: Bearer <SVACER_MCP_TOKEN>. Запросы без токена или с неверным значением получают ответ401и заголовокWWW-Authenticate: Bearer .... Токен является разделяемым секретом и не заменяет TLS, а дополняет его: при работе за обратным прокси необходимо использовать HTTPS, а сам токен передавать только по защищённому каналу. - Без
SVACER_MCP_TOKENHTTP-сервер не запускается. - Учётные данные
admin/adminпредназначены только для тестового стенда. В рабочем окружении необходимо задать собственные логин и пароль через переменные окружения. - Файл
.envне должен добавляться в систему контроля версий.
Передача токена клиентом
Большинство HTTP-клиентов MCP (OpenWebUI и др.) позволяют задать произвольный заголовок Authorization в настройках инструмента — указывается значение Bearer <токен>. Для ручной проверки:
curl -H "Authorization: Bearer $SVACER_MCP_TOKEN" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}' \
http://localhost:8002/mcp
Инструменты
Справочник по 8 инструментам Svacer MCP. Типичный порядок вызовов: get_projects → get_snapshots → любой из аналитических инструментов.
| Инструмент | Назначение |
|---|---|
| get_projects | Список проектов с ветками — точка входа |
| get_snapshots | Снимки конкретной ветки, от нового к старому |
| get_project_stats | Агрегированные метрики снимка: severity / review / checker |
| get_markers | Компактный список маркеров с серверной фильтрацией |
| get_warnings | Полные предупреждения с трассами и историей разметки |
| get_diff | Сравнение двух снимков: new / missing / modified / matched |
| get_advanced_file_preview | Фрагмент исходного кода вокруг строки |
| get_project_groups | Группа проектов по имени или UUID |
get_projects
Список всех проектов с ветками. Точка входа: с этого вызова начинается практически любой сценарий — он возвращает project_id и branch_id, необходимые для последующих запросов.
Параметров нет.
Вызов:
get_projects()
Ответ:
[
{
"project_id": "91630e84-db2f-4d8c-8716-68b7fdf17a66",
"project_name": "bash",
"created": "2021-12-13T13:22:42.122456Z",
"created_by": "admin",
"branches": [
{
"branch_id": "77f66b9e-0453-4ae9-a187-88950b4c4bc4",
"branch_name": "master",
"created": "2021-12-13T13:22:42.394812Z"
}
]
}
]
get_snapshots
Список снимков для конкретной ветки проекта, от нового к старому.
Параметры.
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
| project_id | string (UUID) | да | Из get_projects
|
| branch_id | string (UUID) | да | Из get_projects
|
| name_filter | string | нет | Подстрока или regex для фильтра по имени снимка |
Вызов:
get_snapshots( project_id="91630e84-db2f-4d8c-8716-68b7fdf17a66", branch_id="77f66b9e-0453-4ae9-a187-88950b4c4bc4" )
Ответ:
[
{
"snapshot_id": "b42cb563-86f4-4f96-900a-7782163327c9",
"name": "Snapshot 2020-03-25 09:09:41 +0300",
"import_time": "2020-03-25T09:09:41.837296Z",
"commit_hash": null,
"markers_count": 297,
"link": "https://svacer-demo.ispras.ru/..."
}
]
get_project_stats
Агрегированные метрики по снимку: общее количество предупреждений, распределение по критичности, по статусу разметки, по детекторам. Наиболее быстрый способ получить общую картину по проекту.
Параметры.
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
| project_id | string (UUID) | да | Из get_projects
|
| branch_id | string (UUID) | да | Из get_projects
|
| snapshot_id | string (UUID) | да | Из get_snapshots
|
Вызов:
get_project_stats( project_id="91630e84-db2f-4d8c-8716-68b7fdf17a66", branch_id="77f66b9e-0453-4ae9-a187-88950b4c4bc4", snapshot_id="b42cb563-86f4-4f96-900a-7782163327c9" )
Ответ:
{
"total_warnings": 771,
"by_severity": {
"Critical": 1,
"Major": 1,
"Unspecified": 769
},
"by_review_status": {
"Confirmed": 1,
"False Positive": 1,
"Undecided": 767,
"Unclear": 1,
"Won't fix": 1
},
"by_checker": {
"PROC_USE.VULNERABLE": 337,
"UNUSED_FUNC_RES.REWRITE.MINOR": 44,
"UNREACHABLE_CODE": 28,
"DEREF_AFTER_NULL.EX": 27,
"NULL_AFTER_DEREF": 27
}
}
get_markers
Компактный список маркеров с серверной фильтрацией. Основной инструмент для перечисления и обзора: его следует предпочитать get_warnings, когда не требуются развёрнутые поля — трассы и история разметки.
По умолчанию ответ ограничен 30 маркерами и содержит компактный набор полей. Подробнее об ограничении объёма см. раздел Про объём ответа.
Параметры.
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
| project_id | string (UUID) | да | Из get_projects
|
| branch_id | string (UUID) | да | Из get_projects
|
| snapshot_id | string (UUID) | да | Из get_snapshots
|
| severity | string[] | нет | Critical, Major, Minor, Unspecified. Фильтр по review.severity применяется на стороне коннектора
|
| review | string[] | нет | Confirmed, Won't fix, False Positive, Unclear
|
| warnClass | string[] | нет | Идентификатор детектора (DEREF_AFTER_NULL, …)
|
| file | string[] | нет | Подстрока пути к файлу |
| traces | bool | нет | Включить трассы маркеров |
| checker_info | bool | нет | Включить метаданные детектора (CWE, описание) |
| review_history | bool | нет | Включить историю изменений разметки |
| comment_history | bool | нет | Включить комментарии к маркеру |
| custom_filter | string | нет | Имя или идентификатор сохранённого фильтра из веб-интерфейса Svacer |
| limit | int | нет | Максимальное количество маркеров в ответе (по умолчанию 30). Значение 0 снимает ограничение |
| fields | string[] | нет | Список разрешённых полей маркера верхнего уровня. По умолчанию — компактный набор id, warnClass, file, line, msg, function, review. Значение ["*"] возвращает все поля коннектора (id, warnClass, file, line, msg, tool, function, mtid, review, а также traces/checkerInfo/review_history/comments, если они запрошены). Допустим и произвольный список, например ["id","warnClass"]
|
Вызов:
get_markers( project_id="91630e84-db2f-4d8c-8716-68b7fdf17a66", branch_id="77f66b9e-0453-4ae9-a187-88950b4c4bc4", snapshot_id="b42cb563-86f4-4f96-900a-7782163327c9", warnClass=["PROC_USE.VULNERABLE"] )
Ответ:
{
"total_count": 341,
"returned_count": 30,
"truncated": true,
"filters_applied": {"warnClass": ["PROC_USE.VULNERABLE"]},
"markers": [
{
"id": "e05bb35b-a95e-4eb2-85ae-3101b788f07d",
"warnClass": "PROC_USE.VULNERABLE.TEMP",
"file": "/.build/lib/sh/tmpfile.c",
"line": 160,
"msg": "Use of vulnerable function 'mktemp' at tmpfile.c:160. ...",
"function": "sh_mktmpname",
"review": null
}
]
}
total_count отражает количество маркеров, удовлетворяющих фильтру до применения ограничения; returned_count — количество маркеров, фактически содержащихся в markers. При truncated: true следует либо сузить фильтры (severity, warnClass, file), либо передать limit=0 для получения полного списка. Поля tool и mtid возвращаются только при fields=["*"].
get_warnings
Полные предупреждения с детальной разметкой. Ответ значительно объёмнее, чем у get_markers, поэтому инструмент следует использовать только тогда, когда нужны поля, отсутствующие в компактной форме: traces, review_history, checker_info, comment_history.
Лимит по умолчанию — 30; при включённых traces, review_history или comment_history он автоматически снижается до 8, поскольку такие предупреждения существенно объёмнее.
Параметры.
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
project_id
|
string (UUID) | да | |
branch_id
|
string (UUID) | да | |
snapshot_id
|
string (UUID) | да | |
severity
|
string[]
|
нет | Critical, Major, Minor, Unspecified. Фильтр по review.severity, применяется на стороне коннектора
|
review
|
string[]
|
нет | Confirmed, Won't fix, False Positive, Unclear
|
warnClass
|
string[]
|
нет | Идентификатор детектора |
file
|
string[]
|
нет | Подстрока пути к файлу |
traces
|
bool
|
нет | Включить трассы. Активирует режим расширенных полей (лимит по умолчанию — 8) |
checker_info
|
bool
|
нет | Включить метаданные детектора (CWE, описание) |
review_history
|
bool
|
нет | Включить историю разметки. Режим расширенных полей |
comment_history
|
bool
|
нет | Включить комментарии. Режим расширенных полей |
custom_filter
|
string | нет | Имя или идентификатор сохранённого фильтра |
limit
|
int | нет | Максимальное количество предупреждений в ответе. По умолчанию — 30, в режиме расширенных полей — 8. Значение 0 снимает ограничение. Явно заданное limit отменяет автоматическое снижение
|
fields
|
string[]
|
нет | См. описание у get_markers
|
Вызов:
get_warnings(
project_id="91630e84-db2f-4d8c-8716-68b7fdf17a66",
branch_id="77f66b9e-0453-4ae9-a187-88950b4c4bc4",
snapshot_id="b42cb563-86f4-4f96-900a-7782163327c9",
severity=["Critical"],
review_history=True,
traces=True
)
Ответ:
{
"total_count": 1,
"returned_count": 1,
"truncated": false,
"filters_applied": {"severity": ["Critical"], "traces": true, "review_history": true},
"warnings": [
{
"id": "a3f21c90-1d4e-4b82-9f63-7c8e5d2a1b09",
"warnClass": "DEREF_AFTER_NULL.LOOP",
"file": "/.build/execute_cmd.c",
"line": 3327,
"msg": "Possible null pointer dereference of 'l' after loop exit.",
"function": "select_query",
"review": {"status": "Confirmed", "severity": "Critical"},
"review_history": [{"status": "Confirmed", "changed_by": "admin", "changed_at": "2021-12-13T14:00:00Z"}],
"traces": [{"file": "/.build/execute_cmd.c", "line": 3320, "msg": "Loop starts here; 'l' may exhaust the list."}]
}
]
}
get_diff
Сравнение двух снимков. Категории располагаются под ключом markers: new_markers (появилось в новом снимке), missing_markers (исчезло из нового), modified_markers (тот же идентификатор, изменился контекст), matched_markers (совпало в обоих). Параметры project_id и branch_id не требуются — достаточно UUID снимков.
Параметры.
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
base_snapshot_id
|
string (UUID) | да | Старый снимок |
head_snapshot_id
|
string (UUID) | нет | Новый снимок; если не указан, сравнение выполняется с предыдущим по времени |
level
|
int | нет | 0 — только статистика; 1 — статистика и идентификаторы маркеров; 2 — полные маркеры по категориям
|
checker_info
|
bool | нет | Метаданные детекторов для маркеров (только при level >= 2)
|
limit
|
int | нет | Максимальное количество маркеров на каждую категорию при level >= 2. По умолчанию — 20, значение 0 снимает ограничение. Параметр игнорируется при level < 2
|
fields
|
string[]
|
нет | См. описание у get_markers/get_warnings. Применяется к маркерам внутри категорий при level >= 2
|
Вызов (level=0):
get_diff(
base_snapshot_id="72b3df7b-c15a-4e3d-8f92-a041dc6e5b87",
head_snapshot_id="b42cb563-86f4-4f96-900a-7782163327c9",
level=0
)
Ответ (level=0):
{
"stats": {
"context1": {"projectName": "paho.mqtt.c", "snapshotName": "Snapshot 2020-03-20 ..."},
"context2": {"projectName": "paho.mqtt.c", "snapshotName": "Snapshot 2020-03-25 ..."},
"scope": ["NEW", "MISSING", "MATCHED", "MODIFIED"],
"new": 9,
"missing": 12,
"modified": 98,
"matched": 187
}
}
Ответ (level=2) — каждая категория внутри markers оформляется и ограничивается независимо:
{
"stats": {"new": 50, "missing": 5, "modified": 0, "matched": 187},
"markers": {
"new_markers": {
"total_count": 50,
"returned_count": 20,
"truncated": true,
"markers": [
{"id": "a3f21c90-...", "warnClass": "DEREF_AFTER_NULL.LOOP", "file": "...", "line": 3327, "msg": "...", "function": "select_query", "review": null}
]
},
"missing_markers": {"total_count": 5, "returned_count": 5, "truncated": false, "markers": [...]},
"modified_markers": {"total_count": 0, "returned_count": 0, "truncated": false, "markers": []},
"matched_markers": {"total_count": 187, "returned_count": 20, "truncated": true, "markers": [...]}
}
}
Если требуется полное содержимое категории, следует увеличить limit либо запросить нужные идентификаторы отдельным вызовом get_markers. Маркеры внутри категорий проходят ту же компактную обработку, что и в get_warnings: значение fields=["*"] возвращает фиксированный набор полей коннектора, а не произвольные «сырые» поля API.
get_advanced_file_preview
Фрагмент исходного кода из снимка вокруг указанной строки. Параметры project_id и branch_id не требуются — достаточно идентификатора снимка и пути к файлу.
Параметры.
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
snapshot_id
|
string (UUID) | да | |
file_path
|
string | да | Путь к файлу в том виде, в котором его возвращают get_markers и get_warnings
|
line
|
int | нет | Центральная строка, нумерация с 1 (по умолчанию 1)
|
before
|
int | нет | Количество строк до центральной (по умолчанию 0)
|
after
|
int | нет | Количество строк после центральной (по умолчанию 99999 — до конца файла)
|
Вызов:
get_advanced_file_preview(
snapshot_id="b42cb563-86f4-4f96-900a-7782163327c9",
file_path="/.build/execute_cmd.c",
line=3327,
before=10,
after=10
)
Ответ:
{
"line": 3327,
"content": " for (l = list; l && --reply; l = l->next)\n\t;\n return (l->word->word);\n",
"total_lines": 6082
}
get_project_groups
Получить группу проектов по имени или UUID. Группы объединяют проекты в логические блоки — например, по команде или продукту.
Параметры.
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
name_or_id
|
string | да | Имя группы или её UUID |
Вызов:
get_project_groups(name_or_id="Linux Tools")
Ответ:
{
"project_group_id": "c4f8a2d1-3b7e-4f90-82ac-1d5e8f2b6c04",
"project_group_name": "Linux Tools",
"projects": [
{"id": "91630e84-db2f-4d8c-8716-68b7fdf17a66", "name": "bash"},
{"id": "d3a17f52-...", "name": "coreutils"}
]
}
projects[].id — это project_id, который далее передаётся в get_snapshots. Группы и проекты — разные сущности; идентификатор группы и идентификатор проекта не взаимозаменяемы.
Примеры сценариев
Приведённые ниже запросы выполнены на демонстрационном стенде svacer-demo.ispras.ru с использованием OpenWebUI и модели qwen3-coder:30b. В любом другом MCP-клиенте с моделью достаточной мощности порядок вызовов будет аналогичным.
Про объём ответа
get_markers, get_warnings и get_diff(level=2) по умолчанию ограничивают объём ответа, чтобы не перегружать контекст модели:
get_markersиget_warnings— 30 маркеров по умолчанию. Если уget_warningsвключеныtraces,review_historyилиcomment_history, лимит снижается до 8, поскольку такие маркеры значительно объёмнее.get_diff(level=2)— 20 маркеров на каждую категорию внутриmarkers(new_markers/missing_markers/modified_markers/matched_markers).
В ответе присутствуют поля total_count, returned_count, truncated. При truncated: true есть два варианта действий: сузить фильтр (severity, warnClass, file) либо явно увеличить limit (значение limit=0 полностью снимает ограничение).
Поле fields определяет, какие ключи маркера возвращаются. По умолчанию применяется компактный набор id, warnClass, file, line, msg, function, review (а также traces/checkerInfo/review_history/comments, если они запрошены логическими флагами и пришли с сервера). Для полного маркера со всеми служебными ключами — fields=["*"]. Для произвольной выборки — список полей верхнего уровня, например fields=["id","warnClass"]. Поле review — объект {status, severity, action}; вложенные ключи в fields не поддерживаются, поэтому объект review запрашивается целиком.
Перечислить все проекты
Какие проекты есть в Svacer?
Цепочка вызовов:
get_projects()
Ответ модели:
В Svacer доступно 6 проектов: bash, openssl, paho.mqtt.c, coturn, zstd, darpa. У каждого — одна ветка
master.
Посмотреть снимки проекта
Какие снимки есть у paho.mqtt.c? Самый свежий когда?
Цепочка вызовов:
get_projects()— найтиproject_idиbranch_idget_snapshots(project_id=..., branch_id=...)
Ответ модели:
У paho.mqtt.c 3 снимка. Самый свежий — «Snapshot 2020-03-25 09:09:41 +0300» (297 маркеров). Предыдущий — 20 марта (306 маркеров).
Поле commit_hash может принимать значение null, если проект не сохраняет хэш коммита в custom_properties. Имена снимков произвольны: одни проекты записывают в имя дату, другие — коммит, третьи — свободный текст.
Сводка по проекту
Что в bash в последнем снимке? Сколько всего предупреждений, есть ли критические, какие топ-детекторы?
Цепочка вызовов:
get_projects()get_snapshots(project_id, branch_id)— взять последний снимокget_project_stats(project_id, branch_id, snapshot_id)
Ответ модели:
В последнем снимке bash содержится 771 предупреждение:
- Критических: 1 (Confirmed)
- Major: 1 (Won't fix)
- Остальные: 769 (Unspecified — не размечались)
Топ-детекторы по количеству:
PROC_USE.VULNERABLE— 337UNUSED_FUNC_RES.REWRITE.MINOR— 44UNREACHABLE_CODE— 28DEREF_AFTER_NULL.EX— 27NULL_AFTER_DEREF— 27
Unspecified в by_severity — маркеры без ручной разметки, а не «низкий приоритет». Поле by_checker не сортируется, на большом снимке оно может содержать более 100 ключей — чтобы получить именно топ-N, следует явно сформулировать запрос: «топ-5 детекторов».
Тренд по нескольким снимкам
Как у openssl менялось число предупреждений за последние пять снимков? Покажи таблицей.
Цепочка вызовов:
get_projects()get_snapshots()— взять списокget_project_stats()× 5 — по каждому из последних пяти снимков
Ответ модели:
Снимок Дата Всего 2020-04-30 05:49 30.04.2020 1252 2020-04-30 05:29 30.04.2020 1252 2020-04-30 05:08 30.04.2020 1252 2020-04-30 04:48 30.04.2020 1252 2020-04-30 04:22 30.04.2020 1252
На демонстрационном стенде указанные пять снимков openssl импортированы с интервалом в 20 минут одного дня и полностью идентичны — поэтому динамика отсутствует. На реальном проекте с историей релизов значения будут изменяться.
Найти срабатывания конкретного детектора
Где в bash срабатывает PROC_USE.VULNERABLE? Покажи список — файл, строка, что именно ругается. Достаточно первых десяти.
Цепочка вызовов:
get_projects()get_snapshots()get_markers(warnClass=["PROC_USE.VULNERABLE"])
Ответ модели:
/.build/lib/sh/tmpfile.c:160—mktemp(), race condition. Рекомендуетсяmkstemp()./.build/lib/readline/shell.c:151—getenv(), значение может быть подменено./.build/shell.c:415—getenv()вmain()./.build/lib/readline/complete.c:1516—getenv()./.build/lib/sh/eaccess.c:115—strcat(), рекомендуетсяstrncat(). …
Фильтр warnClass=["PROC_USE.VULNERABLE"] охватывает все подклассы: PROC_USE.VULNERABLE.TEMP, .GETENV, .STRCAT и т. д. — всего 341 маркер. Несколько значений в одном параметре трактуются как логическое «ИЛИ»: severity=["Critical","Major"] возвращает маркеры обеих категорий.
В ответе будет total_count: 341, returned_count: 30, truncated: true — это ожидаемое поведение. Модель видит общий объём по total_count и при необходимости сужает запрос или вызывает get_markers(..., limit=0), чтобы получить полный список.
Сравнить два снимка
Возьми два последних снимка paho.mqtt.c — что между ними изменилось? Сколько новых предупреждений, сколько починили?
Цепочка вызовов:
get_projects()get_snapshots()— два последнихget_diff(base_snapshot_id="72b3df7b-...", head_snapshot_id="b42cb563-...", level=0)
Ответ модели:
Между двумя последними снимками paho.mqtt.c:
- Новых: 12
- Удалённых: 13
- Изменённых: 99
- Совпадающих: 185
Удалено несколько больше, чем добавлено — общая картина практически не изменилась.
Категория modified — маркер, присутствующий в обоих снимках, у которого изменилось окружение (номер строки, контекст функции). Это не новая ошибка. На больших проектах рекомендуется начинать с level=0 для получения статистики, при необходимости использовать level=1 (только идентификаторы маркеров) и затем точечно вызывать get_markers с нужными фильтрами.
level=2 возвращает полные маркеры по категориям, причём каждая категория по умолчанию ограничена 20 маркерами. Категории располагаются внутри markers: new_markers, missing_markers, modified_markers, matched_markers. Структура ответа в JSON: {"markers": {"new_markers": {"total_count": N, "returned_count": ..., "truncated": ..., "markers": [...]}, ...}}. Если требуется полное содержимое категории, следует увеличить limit или выполнить отдельный вызов get_markers по нужным идентификаторам.
Разобрать конкретное предупреждение
В bash есть один подтверждённый критикал — что-то про разыменование указателя. Покажи код вокруг этого места и объясни в чём проблема.
Цепочка вызовов:
get_projects()→get_snapshots()— найти снимок bashget_markers(severity=["Critical"], review=["Confirmed"])get_advanced_file_preview(file_path="/.build/execute_cmd.c", line=3327, before=10, after=10)
Ответ модели:
Маркер
DEREF_AFTER_NULL.LOOPв функцииselect_query(), строка 3327:
for (l = list; l && --reply; l = l->next)
;
return (l->word->word); /* l может быть NULL после выхода из цикла */Если список заканчивается раньше, чем
replyобнуляется,lстанетNULLна последнемl->next, и следующийl->word->word— разыменование нулевого указателя.
file_path должен точно совпадать со значением, возвращённым маркером, включая ведущий префикс /.build/.... Это путь внутри сборочной директории Svacer, а не путь в исходном репозитории; соответствие в репозитории определяется по имени файла.
Для одиночной разметки удобно сразу запрашивать полный маркер с трассами: get_markers(..., severity=["Critical"], review=["Confirmed"], traces=True, checker_info=True). Флаги traces и checker_info указывают серверу включить соответствующие поля в ответ; в выдаче они сохраняются и при значении fields по умолчанию. Значение fields=["*"] требуется лишь в том случае, когда дополнительно нужны tool и mtid — служебные ключи, исключённые из компактного набора.