Пользовательские MCP-инструменты

Пользовательские MCP-инструменты

Создание пользовательских инструментов запросов к CPG для Claude Code и других MCP-клиентов через определение SQL-запросов в YAML-файле. Не требует изменения кода.

Обзор

Динамический загрузчик читает .codegraph/tools.yaml из корня проекта и регистрирует каждое определение как MCP-инструмент. Это позволяет создавать проектно-специфичные запросы анализа, которые Claude Code (или любой MCP-клиент) может вызвать по имени.

Основные возможности: - Определение пользовательских SQL-запросов как именованных MCP-инструментов - Параметры с типами и значениями по умолчанию - Только чтение (только SELECT-запросы) — операции записи отклоняются - Без изменения кода, без перезапуска сервера (инструменты загружаются при старте MCP-сервера)

Быстрый старт

1. Создайте файл инструментов

mkdir -p .codegraph

Создайте .codegraph/tools.yaml:

tools:
  - name: find_large_functions
    description: Найти функции длиннее N строк
    sql: |
      SELECT name, filename, (line_number_end - line_number) as lines
      FROM nodes_method
      WHERE (line_number_end - line_number) > {min_lines}
      ORDER BY lines DESC
      LIMIT {limit}
    parameters:
      - name: min_lines
        type: int
        default: 100
      - name: limit
        type: int
        default: 20

2. Настройте MCP-сервер

Убедитесь, что в config.yaml указано:

mcp:
  enabled: true
  dynamic_tools_path: .codegraph/tools.yaml

3. Запустите MCP-сервер

python -m src.mcp

Инструмент find_large_functions теперь доступен любому MCP-клиенту.

4. Использование из Claude Code

Добавьте в .claude/mcp.json:

{
  "mcpServers": {
    "codegraph": {
      "command": "python",
      "args": ["-m", "src.mcp", "--db", "data/projects/myproject.duckdb"]
    }
  }
}

Затем спросите Claude: «Найди функции длиннее 200 строк» — он вызовет find_large_functions с min_lines=200.

Формат YAML

tools:
  - name: имя_инструмента        # Обязательно: уникальное имя (snake_case)
    description: Описание          # Обязательно: отображается MCP-клиентам
    sql: |                         # Обязательно: SQL-шаблон (только SELECT)
      SELECT ...
      WHERE column > {param}
      LIMIT {limit}
    parameters:                    # Необязательно: параметры инструмента
      - name: param               # Имя параметра (соответствует {param} в SQL)
        type: int                  # Тип: int, str, float
        default: 10                # Значение по умолчанию

Подстановка параметров

Параметры используют синтаксис {имя} в SQL-шаблонах. Подстановка через Python str.format():

sql: |
  SELECT name, filename
  FROM nodes_method
  WHERE CyclomaticComplexity > {threshold}
    AND filename LIKE '%{path_pattern}%'
  LIMIT {limit}
parameters:
  - name: threshold
    type: int
    default: 10
  - name: path_pattern
    type: str
    default: ""
  - name: limit
    type: int
    default: 20

Примеры инструментов

Поиск невызываемых функций

- name: find_uncalled_functions
  description: Найти функции, которые нигде не вызываются
  sql: |
    SELECT m.name, m.filename, m.line_number
    FROM nodes_method m
    LEFT JOIN edges_call e ON m.id = e.dst
    WHERE e.src IS NULL
    ORDER BY m.filename, m.line_number
    LIMIT {limit}
  parameters:
    - name: limit
      type: int
      default: 50

Поиск сложных методов

- name: find_complex_methods
  description: Найти методы с высокой цикломатической сложностью
  sql: |
    SELECT name, filename, CyclomaticComplexity, FanIn, FanOut
    FROM nodes_method
    WHERE CyclomaticComplexity > {threshold}
    ORDER BY CyclomaticComplexity DESC
    LIMIT {limit}
  parameters:
    - name: threshold
      type: int
      default: 15
    - name: limit
      type: int
      default: 30

Поиск опасных вызовов

- name: find_dangerous_calls
  description: Найти вызовы потенциально опасных функций
  sql: |
    SELECT c.callee_name, c.filename, c.line_number, m.name as caller
    FROM nodes_call c
    JOIN nodes_method m ON c.method_id = m.id
    WHERE c.callee_name IN ('strcpy', 'strcat', 'sprintf', 'gets')
    ORDER BY c.callee_name, c.filename
    LIMIT {limit}
  parameters:
    - name: limit
      type: int
      default: 100

Поиск TODO/FIXME

- name: find_todos
  description: Найти методы с маркерами TODO или FIXME
  sql: |
    SELECT name, filename, line_number
    FROM nodes_method
    WHERE HasTodoFixme = true
    ORDER BY filename, line_number
    LIMIT {limit}
  parameters:
    - name: limit
      type: int
      default: 50

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

Гарантия только чтения

Разрешены только SELECT-запросы. Загрузчик валидирует SQL в двух точках:

  1. При загрузке — определения с не-SELECT SQL отклоняются
  2. При выполнении — сгенерированный SQL (после подстановки параметров) проверяется повторно

Запрещённые ключевые слова: INSERT, UPDATE, DELETE, DROP, ALTER, CREATE, TRUNCATE, GRANT, REVOKE.

Ограничение строк

Результаты ограничены значением mcp.max_query_rows (по умолчанию: 1000) для предотвращения исчерпания памяти.

Справочник конфигурации

# config.yaml
mcp:
  enabled: true                           # Включить/выключить MCP-сервер
  transport: stdio                        # Транспорт: stdio | http | websocket
  max_query_rows: 1000                    # Максимум строк на результат запроса
  dynamic_tools_path: .codegraph/tools.yaml  # Путь к YAML с инструментами

Устранение неполадок

Инструмент не появляется? - Проверьте, что .codegraph/tools.yaml существует относительно корня проекта - Проверьте логи MCP-сервера на предупреждения валидации - Убедитесь в наличии mcp.enabled: true и mcp.dynamic_tools_path в config.yaml

SQL отклонён? - Убедитесь, что запрос начинается с SELECT - Проверьте на случайно включённые DDL/DML-ключевые слова - Проверьте соответствие имён параметров между {param} и parameters

Пустые результаты? - Протестируйте SQL напрямую: python -m src.cli gocpg query "ВАШ SQL" - Проверьте имена таблиц и столбцов в Справочнике схемы

Связанная документация


Модуль: src/mcp/dynamic_loader.py Последнее обновление: февраль 2026