Плагин Qwen Code Companion: Спецификация интерфейса
Последнее обновление: 15 сентября 2025 г.
Этот документ определяет контракт для создания плагина-компаньона, который включает режим IDE в Qwen Code. Для VS Code эти функции (нативное сравнение, контекстная осведомленность) предоставляются официальным расширением (marketplace ). Эта спецификация предназначена для разработчиков, которые хотят реализовать аналогичную функциональность в других редакторах, таких как JetBrains IDE, Sublime Text и т. д.
I. Интерфейс связи
Qwen Code и плагин IDE обмениваются данными через локальный канал связи.
1. Транспортный уровень: MCP поверх HTTP
Плагин ДОЛЖЕН запускать локальный HTTP-сервер, который реализует Model Context Protocol (MCP).
- Протокол: Сервер должен быть корректным MCP-сервером. Мы рекомендуем использовать существующий MCP SDK для вашего языка программирования, если таковой доступен.
- Эндпоинт: Сервер должен предоставлять единую точку входа (например,
/mcp) для всего MCP-взаимодействия. - Порт: Сервер ОБЯЗАН слушать динамически назначенный порт (то есть слушать порт
0).
2. Механизм обнаружения: Port File
Для подключения Qwen Code необходимо определить, в каком экземпляре IDE он запущен, и какой порт использует ваш сервер. Плагин ОБЯЗАН обеспечить это, создавая так называемый “discovery file”.
-
Как CLI находит файл: CLI определяет Process ID (PID) родительского процесса IDE, проходя по дереву процессов. Затем он ищет discovery файл, имя которого содержит этот PID.
-
Расположение файла: Файл должен быть создан в определённой директории:
os.tmpdir()/qwen/ide/. Ваш плагин должен создать эту директорию, если она не существует. -
Соглашение об именовании файла: Имя файла критично и ДОЛЖНО соответствовать шаблону:
qwen-code-ide-server-${PID}-${PORT}.json${PID}: Process ID родительского процесса IDE. Плагин должен определить этот PID и включить его в имя файла.${PORT}: Порт, на котором слушает ваш MCP сервер.
-
Содержимое файла и проверка workspace: Файл ОБЯЗАН содержать JSON объект следующей структуры:
{ "port": 12345, "workspacePath": "/path/to/project1:/path/to/project2", "authToken": "a-very-secret-token", "ideInfo": { "name": "vscode", "displayName": "VS Code" } }port(число, обязательное): Порт MCP сервера.workspacePath(строка, обязательная): Список корневых путей открытых workspace, разделённых системным разделителем путей (:для Linux/macOS,;для Windows). CLI использует этот путь, чтобы убедиться, что он запущен в той же папке проекта, что и открытая в IDE. Если текущая рабочая директория CLI не является подкаталогомworkspacePath, соединение будет отклонено. Плагин ОБЯЗАН предоставить правильные абсолютные пути к корню открытых workspace.authToken(строка, обязательная): Секретный токен для защиты соединения. CLI будет включать этот токен в заголовокAuthorization: Bearer <token>во всех запросах.ideInfo(объект, обязательный): Информация о IDE.name(строка, обязательная): Краткий идентификатор IDE в нижнем регистре (например,vscode,jetbrains).displayName(строка, обязательная): Удобочитаемое имя IDE (например,VS Code,JetBrains IDE).
-
Аутентификация: Для защиты соединения плагин ОБЯЗАН генерировать уникальный секретный токен и включать его в discovery файл. CLI затем будет использовать этот токен в заголовке
Authorizationдля всех запросов к MCP серверу (например,Authorization: Bearer a-very-secret-token). Ваш сервер ОБЯЗАН проверять этот токен при каждом запросе и отклонять неавторизованные. -
Разрешение конфликтов через переменные окружения (рекомендуется): Для наиболее надёжной работы ваш плагин РЕКОМЕНДУЕТСЯ одновременно создавать discovery файл и устанавливать переменную окружения
QWEN_CODE_IDE_SERVER_PORTв интегрированном терминале. Файл служит основным механизмом обнаружения, но переменная окружения играет ключевую роль при разрешении конфликтов. Если пользователь открыл несколько окон IDE для одного и того же workspace, CLI использует переменнуюQWEN_CODE_IDE_SERVER_PORT, чтобы определить и подключиться к серверу нужного окна.
II. Интерфейс контекста
Чтобы включить осведомленность о контексте, плагин МОЖЕТ предоставлять CLI информацию в реальном времени об активности пользователя в IDE.
Уведомление ide/contextUpdate
Плагин МОЖЕТ отправлять уведомление ide/contextUpdate notification в CLI при каждом изменении контекста пользователя.
-
События-триггеры: Это уведомление следует отправлять (рекомендуется использовать debounce 50 мс) при следующих условиях:
- Открытие, закрытие или фокусировка файла.
- Изменение позиции курсора или выделенного текста в активном файле.
-
Полезная нагрузка (
IdeContext): Параметры уведомления ДОЛЖНЫ быть объектом типаIdeContext:interface IdeContext { workspaceState?: { openFiles?: File[]; isTrusted?: boolean; }; } interface File { // Абсолютный путь к файлу path: string; // Временная метка последнего фокуса (для сортировки) timestamp: number; // true, если это текущий активный файл isActive?: boolean; cursor?: { // Номер строки (начинается с 1) line: number; // Номер символа (начинается с 1) character: number; }; // Текст, выбранный пользователем selectedText?: string; }Примечание: Список
openFilesдолжен содержать только файлы, которые существуют на диске. Виртуальные файлы (например, несохраненные файлы без пути, страницы настроек редактора) ДОЛЖНЫ быть исключены.
Как CLI использует этот контекст
После получения объекта IdeContext CLI выполняет несколько шагов нормализации и усечения перед отправкой информации в модель.
- Порядок файлов: CLI использует поле
timestamp, чтобы определить самые последние открытые файлы. Он сортирует списокopenFilesпо этому значению. Поэтому ваш плагин ОБЯЗАН предоставлять точную метку времени Unix для момента, когда файл был в фокусе последний раз. - Активный файл: CLI считает только самый последний файл (после сортировки) “активным”. Он игнорирует флаг
isActiveу всех остальных файлов и очищает их поляcursorиselectedText. Ваш плагин должен устанавливатьisActive: trueи предоставлять данные о курсоре/выделении только для файла, который сейчас в фокусе. - Усечение: Чтобы уложиться в лимиты токенов, CLI обрезает список файлов (до 10 файлов) и
selectedText(до 16 КБ).
Хотя CLI сам выполняет финальное усечение, мы настоятельно рекомендуем вашему плагину также ограничивать объем отправляемого контекста.
III. Интерфейс сравнения (Diffing Interface)
Чтобы включить интерактивные изменения кода, плагин МОЖЕТ предоставлять интерфейс сравнения. Это позволяет CLI запрашивать у IDE открытие представления diff, показывающего предложенные изменения в файле. Затем пользователь может просмотреть, отредактировать, а в конечном итоге принять или отклонить эти изменения непосредственно в IDE.
Инструмент openDiff
Плагин ОБЯЗАН зарегистрировать инструмент openDiff на своем MCP-сервере.
-
Описание: Этот инструмент указывает IDE открыть изменяемое представление diff для определенного файла.
-
Запрос (
OpenDiffRequest): Инструмент вызывается через запросtools/call. Полеargumentsвparamsзапроса ДОЛЖНО быть объектом типаOpenDiffRequest.interface OpenDiffRequest { // Абсолютный путь к файлу, по которому будет показан diff. filePath: string; // Предлагаемое новое содержимое файла. newContent: string; } -
Ответ (
CallToolResult): Инструмент ОБЯЗАН немедленно вернутьCallToolResult, чтобы подтвердить получение запроса и сообщить, успешно ли было открыто представление diff.- В случае успеха: Если представление diff было успешно открыто, ответ ДОЛЖЕН содержать пустой контент (т.е.
content: []). - В случае ошибки: Если ошибка помешала открытию представления diff, ответ ДОЛЖЕН иметь
isError: trueи включать блокTextContentв массивеcontent, описывающий ошибку.
Фактический результат применения diff (принятие или отклонение) передается асинхронно через уведомления.
- В случае успеха: Если представление diff было успешно открыто, ответ ДОЛЖЕН содержать пустой контент (т.е.
Инструмент closeDiff
Плагин ОБЯЗАН зарегистрировать инструмент closeDiff на своем MCP-сервере.
-
Описание: Этот инструмент указывает IDE закрыть открытую diff-панель для указанного файла.
-
Запрос (
CloseDiffRequest): Инструмент вызывается через запросtools/call. Полеargumentsвнутриparamsзапроса ОБЯЗАНО быть объектом типаCloseDiffRequest.interface CloseDiffRequest { // Абсолютный путь к файлу, diff-панель которого нужно закрыть. filePath: string; } -
Ответ (
CallToolResult): Инструмент ОБЯЗАН вернутьCallToolResult.- При успешном выполнении: Если diff-панель была успешно закрыта, ответ ОБЯЗАН содержать один блок TextContent в массиве
content, содержащий финальное содержимое файла перед закрытием. - При ошибке: Если ошибка помешала закрыть diff-панель, ответ ОБЯЗАН иметь
isError: trueи включать блокTextContentв массивеcontent, описывающий ошибку.
- При успешном выполнении: Если diff-панель была успешно закрыта, ответ ОБЯЗАН содержать один блок TextContent в массиве
Уведомление ide/diffAccepted
Когда пользователь принимает изменения в diff-просмотре (например, нажимает кнопку “Apply” или “Save”), плагин ОБЯЗАН отправить уведомление ide/diffAccepted в CLI.
-
Payload: Параметры уведомления ОБЯЗАНЫ включать путь к файлу и финальное содержимое файла. Содержимое может отличаться от оригинального
newContent, если пользователь внес правки вручную в diff-просмотре.{ // Абсолютный путь к файлу, по которому был построен diff. filePath: string; // Полное содержимое файла после принятия изменений. content: string; }
Уведомление ide/diffRejected
Когда пользователь отклоняет изменения (например, закрывает diff-просмотр без применения), плагин ОБЯЗАН отправить уведомление ide/diffRejected в CLI.
-
Payload: Параметры уведомления ОБЯЗАНЫ включать путь к файлу отклонённого diff.
{ // Абсолютный путь к файлу, по которому был построен diff. filePath: string; }
IV. Интерфейс жизненного цикла
Плагин ДОЛЖЕН правильно управлять своими ресурсами и файлом обнаружения в соответствии с жизненным циклом IDE.
- При активации (запуск IDE/включение плагина):
- Запустить MCP сервер.
- Создать файл обнаружения.
- При деактивации (выключение IDE/отключение плагина):
- Остановить MCP сервер.
- Удалить файл обнаружения.