Help:13-alpha MCP: Difference between revisions

From Svacer Wiki
No edit summary
Line 188: Line 188:


== Инструменты ==
== Инструменты ==
Справочник по 8 инструментам Svacer MCP. Типичный порядок вызовов: <code>get_projects</code> → <code>get_snapshots</code> → любой из аналитических инструментов.
{| class="wikitable"
!Инструмент
!Назначение
|-
|<code>get_projects</code>
|Список проектов с ветками — точка входа
|-
|<code>get_snapshots</code>
|Снимки конкретной ветки, от нового к старому
|-
|<code>get_project_stats</code>
|Агрегированные метрики снимка: severity / review / checker
|-
|<code>get_markers</code>
|Компактный список маркеров с серверной фильтрацией
|-
|<code>get_warnings</code>
|Полные предупреждения с трассами и историей ревью
|-
|<code>get_diff</code>
|Сравнение двух снимков: new / missing / modified / matched
|-
|<code>get_advanced_file_preview</code>
|Фрагмент исходного кода вокруг строки
|-
|<code>get_project_groups</code>
|Группа проектов по имени или UUID
|}
=== get_projects ===
Список всех проектов с ветками. Точка входа: с этого вызова начинается практически любой сценарий — он возвращает <code>project_id</code> и <code>branch_id</code>, необходимые для последующих запросов.
'''Параметров нет.'''
'''Вызов:'''
<code>get_projects()</code>
'''Ответ:'''
<code>[
  {
    "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"
      }
    ]
  }
]</code>
----
=== get_snapshots ===
Список снимков для конкретной ветки проекта, от нового к старому.
'''Параметры.'''
{| class="wikitable"
!Имя
!Тип
!Обязательный
!Описание
|-
|<code>project_id</code>
|string (UUID)
|да
|Из <code>get_projects</code>
|-
|<code>branch_id</code>
|string (UUID)
|да
|Из <code>get_projects</code>
|-
|<code>name_filter</code>
|string
|нет
|Подстрока или regex для фильтра по имени снимка
|}
'''Вызов:'''
<code>get_snapshots(
  project_id="91630e84-db2f-4d8c-8716-68b7fdf17a66",
  branch_id="77f66b9e-0453-4ae9-a187-88950b4c4bc4"
)</code>
'''Ответ:'''
<code>[
  {
    "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": "<nowiki>https://svacer-demo.ispras.ru/</nowiki>..."
  }
]</code>
----
=== get_project_stats ===
Агрегированные метрики по снимку: общее количество предупреждений, распределение по критичности, по статусу ревью, по детекторам. Наиболее быстрый способ получить общую картину по проекту.
'''Параметры.'''
{| class="wikitable"
!Имя
!Тип
!Обязательный
!Описание
|-
|<code>project_id</code>
|string (UUID)
|да
|
|-
|<code>branch_id</code>
|string (UUID)
|да
|
|-
|<code>snapshot_id</code>
|string (UUID)
|да
|
|}
'''Вызов:'''
<code>get_project_stats(
  project_id="91630e84-db2f-4d8c-8716-68b7fdf17a66",
  branch_id="77f66b9e-0453-4ae9-a187-88950b4c4bc4",
  snapshot_id="b42cb563-86f4-4f96-900a-7782163327c9"
)</code>
'''Ответ:'''
<code>{
  "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
  }
}</code>
----
=== get_markers ===
Компактный список маркеров с серверной фильтрацией. Основной инструмент для перечисления и обзора: его следует предпочитать <code>get_warnings</code>, когда не требуются развёрнутые поля — трассы и история ревью.
По умолчанию ответ ограничен 30 маркерами и содержит компактный набор полей. Подробнее об ограничении объёма см. раздел Про объём ответа в сценариях.
'''Параметры.'''
{| class="wikitable"
!Имя
!Тип
!Обязательный
!Описание
|-
|<code>project_id</code>
|string (UUID)
|да
|
|-
|<code>branch_id</code>
|string (UUID)
|да
|
|-
|<code>snapshot_id</code>
|string (UUID)
|да
|
|-
|<code>severity</code>
|<code>string[]</code>
|нет
|<code>Critical</code>, <code>Major</code>, <code>Minor</code>, <code>Unspecified</code>. Фильтр по <code>review.severity</code>, применяется на стороне коннектора
|-
|<code>review</code>
|<code>string[]</code>
|нет
|<code>Confirmed</code>, <code>Won't fix</code>, <code>False Positive</code>, <code>Unclear</code>
|-
|<code>warnClass</code>
|<code>string[]</code>
|нет
|Идентификатор детектора (<code>DEREF_AFTER_NULL</code>, …)
|-
|<code>file</code>
|<code>string[]</code>
|нет
|Подстрока пути к файлу
|-
|<code>traces</code>
|<code>bool</code>
|нет
|Включить трассы маркеров
|-
|<code>checker_info</code>
|<code>bool</code>
|нет
|Включить метаданные детектора (CWE, описание)
|-
|<code>review_history</code>
|<code>bool</code>
|нет
|Включить историю изменений ревью
|-
|<code>comment_history</code>
|<code>bool</code>
|нет
|Включить комментарии к маркеру
|-
|<code>custom_filter</code>
|string
|нет
|Имя или идентификатор сохранённого фильтра из веб-интерфейса Svacer
|-
|<code>limit</code>
|int
|нет
|Максимальное количество маркеров в ответе (по умолчанию <code>30</code>). Значение <code>0</code> снимает ограничение
|-
|<code>fields</code>
|<code>string[]</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>
|}
'''Вызов:'''
<code>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"]
)</code>
'''Ответ:'''
<code>{
  "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
    }
  ]
}</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>.
----
=== get_warnings ===
Полные предупреждения с детальной разметкой. Ответ значительно объёмнее, чем у <code>get_markers</code>, поэтому инструмент следует использовать только тогда, когда нужны поля, отсутствующие в компактной форме: <code>traces</code>, <code>review_history</code>, <code>checker_info</code>, <code>comment_history</code>.
Лимит по умолчанию — 30; при включённых <code>traces</code>, <code>review_history</code> или <code>comment_history</code> он автоматически снижается до 8, поскольку такие предупреждения существенно объёмнее.
'''Параметры.'''
{| class="wikitable"
!Имя
!Тип
!Обязательный
!Описание
|-
|<code>project_id</code>
|string (UUID)
|да
|
|-
|<code>branch_id</code>
|string (UUID)
|да
|
|-
|<code>snapshot_id</code>
|string (UUID)
|да
|
|-
|<code>severity</code>
|<code>string[]</code>
|нет
|<code>Critical</code>, <code>Major</code>, <code>Minor</code>, <code>Unspecified</code>. Фильтр по <code>review.severity</code>, применяется на стороне коннектора
|-
|<code>review</code>
|<code>string[]</code>
|нет
|<code>Confirmed</code>, <code>Won't fix</code>, <code>False Positive</code>, <code>Unclear</code>
|-
|<code>warnClass</code>
|<code>string[]</code>
|нет
|Идентификатор детектора
|-
|<code>file</code>
|<code>string[]</code>
|нет
|Подстрока пути к файлу
|-
|<code>traces</code>
|<code>bool</code>
|нет
|Включить трассы. Активирует режим расширенных полей (лимит по умолчанию — 8)
|-
|<code>checker_info</code>
|<code>bool</code>
|нет
|Включить метаданные детектора (CWE, описание)
|-
|<code>review_history</code>
|<code>bool</code>
|нет
|Включить историю ревью. Режим расширенных полей
|-
|<code>comment_history</code>
|<code>bool</code>
|нет
|Включить комментарии. Режим расширенных полей
|-
|<code>custom_filter</code>
|string
|нет
|Имя или идентификатор сохранённого фильтра
|-
|<code>limit</code>
|int
|нет
|Максимальное количество предупреждений в ответе. По умолчанию — <code>30</code>, в режиме расширенных полей — <code>8</code>. Значение <code>0</code> снимает ограничение. Явно заданное <code>limit</code> отменяет автоматическое снижение
|-
|<code>fields</code>
|<code>string[]</code>
|нет
|См. описание у <code>get_markers</code>
|}
'''Вызов:'''
<code>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
)</code>
'''Ответ:'''
<code>{
  "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."}]
    }
  ]
}</code>
----
=== get_diff ===
Сравнение двух снимков. Категории располагаются под ключом <code>markers</code>: <code>new_markers</code> (появилось в новом снимке), <code>missing_markers</code> (исчезло из нового), <code>modified_markers</code> (тот же идентификатор, изменился контекст), <code>matched_markers</code> (совпало в обоих). Параметры <code>project_id</code> и <code>branch_id</code> не требуются — достаточно UUID снимков.
'''Параметры.'''
{| class="wikitable"
!Имя
!Тип
!Обязательный
!Описание
|-
|<code>base_snapshot_id</code>
|string (UUID)
|да
|Старый снимок
|-
|<code>head_snapshot_id</code>
|string (UUID)
|нет
|Новый снимок; если не указан, сравнение выполняется с предыдущим по времени
|-
|<code>level</code>
|int
|нет
|<code>0</code> — только статистика; <code>1</code> — статистика и идентификаторы маркеров; <code>2</code> — полные маркеры по категориям
|-
|<code>checker_info</code>
|bool
|нет
|Метаданные детекторов для маркеров (только при <code>level >= 2</code>)
|-
|<code>limit</code>
|int
|нет
|Максимальное количество маркеров '''на каждую категорию''' при <code>level >= 2</code>. По умолчанию — <code>20</code>, значение <code>0</code> снимает ограничение. Параметр игнорируется при <code>level < 2</code>
|-
|<code>fields</code>
|<code>string[]</code>
|нет
|См. описание у <code>get_markers</code>/<code>get_warnings</code>. Применяется к маркерам внутри категорий при <code>level >= 2</code>
|}
'''Вызов (<code>level=0</code>):'''
<code>get_diff(
  base_snapshot_id="72b3df7b-c15a-4e3d-8f92-a041dc6e5b87",
  head_snapshot_id="b42cb563-86f4-4f96-900a-7782163327c9",
  level=0
)</code>
'''Ответ (<code>level=0</code>):'''
<code>{
  "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
  }
}</code>
'''Ответ (<code>level=2</code>)''' — каждая категория внутри <code>markers</code> оформляется и ограничивается независимо:
<code>{
  "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": [...]}
  }
}</code>
Если требуется полное содержимое категории, следует увеличить <code>limit</code> либо запросить нужные идентификаторы отдельным вызовом <code>get_markers</code>. Маркеры внутри категорий проходят ту же компактную обработку, что и в <code>get_warnings</code>: значение <code>fields=["*"]</code> возвращает фиксированный набор полей коннектора, а не произвольные «сырые» поля API.
----
=== get_advanced_file_preview ===
Фрагмент исходного кода из снимка вокруг указанной строки. Параметры <code>project_id</code> и <code>branch_id</code> не требуются — достаточно идентификатора снимка и пути к файлу.
'''Параметры.'''
{| class="wikitable"
!Имя
!Тип
!Обязательный
!Описание
|-
|<code>snapshot_id</code>
|string (UUID)
|да
|
|-
|<code>file_path</code>
|string
|да
|Путь к файлу в том виде, в котором его возвращают <code>get_markers</code> и <code>get_warnings</code>
|-
|<code>line</code>
|int
|нет
|Центральная строка, нумерация с 1 (по умолчанию <code>1</code>)
|-
|<code>before</code>
|int
|нет
|Количество строк до центральной (по умолчанию <code>0</code>)
|-
|<code>after</code>
|int
|нет
|Количество строк после центральной (по умолчанию <code>99999</code> — до конца файла)
|}
'''Вызов:'''
<code>get_advanced_file_preview(
  snapshot_id="b42cb563-86f4-4f96-900a-7782163327c9",
  file_path="/.build/execute_cmd.c",
  line=3327,
  before=10,
  after=10
)</code>
'''Ответ:'''
<code>{
  "line": 3327,
  "content": "      for (l = list; l && --reply; l = l->next)\n\t;\n      return (l->word->word);\n",
  "total_lines": 6082
}</code>
----
=== get_project_groups ===
Получить группу проектов по имени или UUID. Группы объединяют проекты в логические блоки — например, по команде или продукту.
'''Параметры.'''
{| class="wikitable"
!Имя
!Тип
!Обязательный
!Описание
|-
|<code>name_or_id</code>
|string
|да
|Имя группы или её UUID
|}
'''Вызов:'''
<code>get_project_groups(name_or_id="Linux Tools")</code>
'''Ответ:'''
<code>{
  "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"}
  ]
}</code>
<code>projects[].id</code> — это <code>project_id</code>, который далее передаётся в <code>get_snapshots</code>. Группы и проекты — разные сущности; идентификатор группы и идентификатор проекта не взаимозаменяемы.
== Примеры сценариев ==
== Примеры сценариев ==

Revision as of 10:54, 21 May 2026

Архитектура

MCP — открытый стандарт, через который LLM-клиенты (Claude Desktop, Cursor, VS Code, OpenWebUI и др.) вызывают внешние инструменты. Svacer MCP соединяет одно с другим: 8 инструментов поверх публичного REST API Svacer, которые LLM выбирает и вызывает в ответ на обычный текстовый запрос. Вместо ручной последовательности «открыть UI, найти проект, выбрать снимок, применить фильтр» достаточно сформулировать вопрос в чате, например, «сколько критических предупреждений в последнем снимке bash?», и получить ответ. Необходимые вызовы инструментов модель выполняет самостоятельно.

architectureMCP
Архитектура MCP-сервер

Поток запроса: 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

  1. Развернуть через Docker (см. «Режим HTTP» выше).
  2. Открыть Settings → Tools (или Admin Panel → Settings → Tools).
  3. Добавить сервер:
    • http://localhost:8002/mcp — если OpenWebUI работает на хосте, снаружи Docker.
    • http://svacer-mcp:8000/mcp — если OpenWebUI развёрнут в той же compose-сети, что и svacer-mcp (имя берётся из docker-compose.yml → service name, порт 8000 — внутренний порт контейнера).
  4. Тип подключения: MCP (Streamable HTTP).
  5. В настройках инструмента указать заголовок Authorization: Bearer <SVACER_MCP_TOKEN> (значение — то же, что в .env сервера).
  6. Сохранить — инструменты появятся в чате.

Конфигурация

Переменная По умолчанию Описание
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_TOKEN HTTP-сервер не запускается.
  • Учётные данные 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_projectsget_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) да
branch_id string (UUID) да
snapshot_id string (UUID) да

Вызов:

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) да
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[] нет Идентификатор детектора (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. Группы и проекты — разные сущности; идентификатор группы и идентификатор проекта не взаимозаменяемы.

Примеры сценариев