Skip to content

MCP-сервер для AI-агентов

mcp-server/ — это Model Context Protocol сервер, оборачивающий CLI gitflic в типизированные тулзы для AI-агентов (Claude Code, Cursor и т.п.).

Что внутри

mcp-server/
├── server.mjs              # MCP stdio сервер
├── tools.mjs               # описания тулзов (имя, описание, JSON-схема)
├── runner.mjs              # child_process-обёртка: node <gitflic CLI> <args>
├── project-resolver.mjs    # авто-резолв project из git remote
└── __tests__/              # vitest

77 инструментов — каждый маппится 1-в-1 на подкоманду CLI.

Установка и запуск

Сервер опубликован в npm как gitflic-cli-mcp и запускается через npx — ставить ничего не нужно:

bash
GITFLIC_TOKEN="xxxx" npx -y gitflic-cli-mcp

npx сам подтянет gitflic-cli-mcp и его зависимости (@modelcontextprotocol/sdk, zod) и сам CLI gitflic-cli. Из исходников — то же самое вручную:

bash
cd mcp-server && npm install
GITFLIC_TOKEN="xxxx" node server.mjs

Настройка токена

MCP-сервер наследует GITFLIC_TOKEN от родительского процесса — так же, как CLI:

bash
export GITFLIC_TOKEN="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

Если токен лежит в OS keychain (через gitflic auth login), MCP-сервер тоже его увидит — он запускает gitflic CLI как subprocess, а тот умеет резолвить из keychain.

Конфигурация в Claude Code / Cursor

Claude Code

Одной командой:

bash
claude mcp add gitflic --env GITFLIC_TOKEN=xxxxxxxx -- npx -y gitflic-cli-mcp

Или вручную в ~/.claude.json:

json
{
  "mcpServers": {
    "gitflic": {
      "command": "npx",
      "args": ["-y", "gitflic-cli-mcp"],
      "env": {
        "GITFLIC_TOKEN": "xxxxxxxx"
      }
    }
  }
}

Cursor

В ~/.cursor/mcp.json:

json
{
  "mcpServers": {
    "gitflic": {
      "command": "npx",
      "args": ["-y", "gitflic-cli-mcp"],
      "env": {
        "GITFLIC_TOKEN": "xxxxxxxx"
      }
    }
  }
}

Из исходников вместо npx -y gitflic-cli-mcp укажи "command": "node", "args": ["/path/to/gitflic-cli/mcp-server/server.mjs"].

Примеры использования (в Claude Code)

После подключения агент получает доступ к 77 тулам. Несколько типичных сценариев:

> Создай MR из текущей ветки в main с описанием из последнего коммита

> Найди все открытые MR в проекте FerdBur/wave, которые ждут моего approve

> Закрой все issue старше 60 дней, которые в статусе OPEN и без assignee

Агент сам составляет правильные аргументы, валидирует результат, итерирует при ошибках.

Авто-резолв проекта

mcp-server/project-resolver.mjs автоматически определяет owner/alias из git remote get-url origin — агенту не нужно каждый раз передавать --project:

bash
cd ~/code/FerdBur/wave
# Агент теперь работает с FerdBur/wave по умолчанию для всех команд.

Безопасность

MCP-сервер — тонкая прослойка: каждая тулза маппится 1-в-1 на CLI. Всё, что CLI может сделать, может и MCP-хост. Это и фича, и риск — следите за:

  • Кто имеет доступ к MCP-хосту (любой промпт там может вызвать тулзы).
  • Scope токена (минимизируйте: PROJECT_READ для read-only агентов).
  • Не давайте токен с ADMIN_* scope без крайней нужды.

Что в планах

  • ❌ OAuth browser flow для токена (вместо env-var).
  • ❌ Read-only mode (отдельный MCP-сервер с фильтром tools = только read-*).
  • ❌ Audit log (кто какую тулзу вызвал).

Если нужно — issue/PR.

Annotations: деструктивные операции требуют approval

Все 77 тулов помечены MCP-аннотациями (MCP 2025-06-18 spec):

json
{
  "name": "gitflic_mr_close",
  "annotations": {
    "title": "MR Close",
    "readOnlyHint": false,
    "destructiveHint": true,   // ← клиент запросит подтверждение
    "idempotentHint": true,    // повторный вызов = то же состояние
    "openWorldHint": true      // ходит в GitFlic API
  }
}
HintКогда trueКогда false
readOnlyHintlist / get / view / search / me / statuscreate / edit / delete / merge
destructiveHint(почти всегда — дефолт)только чисто read-only тулзы
idempotentHintclose / cancel / delete / bind / set (повтор → то же состояние)approve (toggle), pipeline start (новый run)
openWorldHintлюбой тул, ходящий в GitFlic APIтолько локальные (auth login/logout, alias set, cache clear)

Что это даёт

Хосты вроде Claude Code и Cursor при получении тулза с destructiveHint: true показывают пользователю prompt:

gitflic_mr_close wants to close merge request #42 on project FerdBur/wave.

Approve? [y/N]

Это защита от runaway-агентов, которые могут снести прод случайным вызовом mr_close или issue_delete.

Как это работает внутри

Аннотации живут в mcp-server/tools.mjs рядом с каждым тулзом:

js
{
  name: "gitflic_mr_close",
  description: "...",
  inputSchema: { ... },
  annotations: {
    title: "MR Close",
    readOnlyHint: false,
    destructiveHint: true,
    idempotentHint: true,
    openWorldHint: true,
  },
  handler: (a) => ["mr", "close", a.localId, "--project", a.project],
}

server.mjs пробрасывает annotations в server.tool(name, desc, schema, annotations, handler) — MCP SDK v1.x их нативно поддерживает и шлёт хосту в tools/list ответе.

Re-classification after adding new tools

Если добавляешь новый тул в tools.mjs, прогони классификатор:

bash
node scripts/annotate-mcp-tools.mjs

Скрипт идёт по TOOLS-массиву, классифицирует каждый по суффиксу/префиксу имени, и вставляет annotations: {...} если его ещё нет. Полностью идемпотентен — повторный запуск ничего не дублирует.

Логика классификации — в scripts/annotate-mcp-tools.mjs (~150 LOC, без зависимостей).

Caveats

  • destructiveHint не означает "обязательно удалит" — это hint, что может. Хосты используют его для UI prompt, но не для блокировки.
  • Если хост не поддерживает annotations (старые версии), всё работает как раньше — annotations просто игнорируются.
  • idempotentHint используется MCP-хостами для авто-retry, но в нашей реализации retry сам делает CLI (через GITFLIC_HTTP_RETRIES). Так что это скорее hint для пользователя.

MIT License