Qwen Code Companion 插件:接口规范
最后更新:2025年9月15日
本文档定义了构建配套插件以启用 Qwen Code IDE 模式的契约。对于 VS Code,这些功能(原生差异对比、上下文感知)由官方扩展提供(市场链接 )。本规范适用于希望为其他编辑器(如 JetBrains IDE、Sublime Text 等)带来类似功能的贡献者。
一、通信接口
Qwen Code 与 IDE 插件通过本地通信通道进行通信。
1. 传输层:基于 HTTP 的 MCP
插件必须运行一个本地 HTTP 服务器,实现 Model Context Protocol (MCP)。
- 协议: 该服务器必须是一个有效的 MCP 服务器。如果可用,我们建议使用适用于你所选语言的现有 MCP SDK。
- 端点: 服务器应为所有 MCP 通信暴露一个单一端点(例如,
/mcp)。 - 端口: 服务器必须监听动态分配的端口(即监听端口
0)。
2. 发现机制:端口文件
为了让通义灵码连接,它需要发现其运行所在的 IDE 实例以及服务器使用的端口。插件必须通过创建一个“发现文件”来实现这一点。
-
CLI 如何找到该文件: CLI 会通过遍历进程树确定其所运行的 IDE 的进程 ID(PID)。然后查找包含此 PID 的发现文件。
-
文件位置: 文件必须在特定目录中创建:
os.tmpdir()/qwen/ide/。如果该目录不存在,插件必须自行创建。 -
文件命名规范: 文件名至关重要且必须遵循以下模式:
qwen-code-ide-server-${PID}-${PORT}.json${PID}:父级 IDE 进程的进程 ID。插件必须确定此 PID 并将其包含在文件名中。${PORT}:MCP 服务器监听的端口号。
-
文件内容与工作区验证: 文件必须包含具有以下结构的 JSON 对象:
{ "port": 12345, "workspacePath": "/path/to/project1:/path/to/project2", "authToken": "a-very-secret-token", "ideInfo": { "name": "vscode", "displayName": "VS Code" } }port(数字,必填):MCP 服务器的端口。workspacePath(字符串,必填):所有打开的工作区根路径列表,使用操作系统特定的路径分隔符分隔(Linux/macOS 使用:,Windows 使用;)。CLI 使用此路径确保其运行于与 IDE 中打开相同的项目文件夹中。如果 CLI 当前工作目录不是workspacePath的子目录,则连接将被拒绝。插件必须提供正确的、绝对的已打开工作区根路径。authToken(字符串,必填):用于保护连接的安全令牌。CLI 将在所有请求中的Authorization: Bearer <token>头部中包含此令牌。ideInfo(对象,必填):关于 IDE 的信息。name(字符串,必填):IDE 的简短小写标识符(例如,vscode、jetbrains)。displayName(字符串,必填):用户友好的 IDE 名称(例如,VS Code、JetBrains IDE)。
-
身份验证: 为了保障连接安全,插件必须生成唯一的秘密令牌并将其包含在发现文件中。CLI 随后会在对 MCP 服务器的所有请求中,在
Authorization头部中包含此令牌(例如,Authorization: Bearer a-very-secret-token)。您的服务器必须在每个请求上验证此令牌,并拒绝任何未经授权的请求。 -
环境变量用于打破平局(推荐做法): 为获得最可靠的体验,插件应同时创建发现文件并在集成终端中设置
QWEN_CODE_IDE_SERVER_PORT环境变量。文件作为主要的发现机制,但环境变量对于打破平局至关重要。如果用户针对同一工作区打开了多个 IDE 窗口,CLI 会使用QWEN_CODE_IDE_SERVER_PORT变量识别并连接到正确窗口的服务器。
II. 上下文接口
为了实现上下文感知,插件可以向 CLI 提供有关用户在 IDE 中活动的实时信息。
ide/contextUpdate 通知
当用户上下文发生变化时,插件可以向 CLI 发送 ide/contextUpdate 通知 。
-
触发事件: 在以下情况下应发送此通知(建议防抖时间为 50ms):
- 文件被打开、关闭或获得焦点。
- 用户在活动文件中的光标位置或文本选择发生更改。
-
负载(
IdeContext): 通知参数必须是一个IdeContext对象:interface IdeContext { workspaceState?: { openFiles?: File[]; isTrusted?: boolean; }; } interface File { // 文件的绝对路径 path: string; // 最后聚焦的 Unix 时间戳(用于排序) 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(截断至 16KB)进行截断。
虽然 CLI 会处理最终的截断操作,但强烈建议你的插件也限制所发送上下文的数量。
III. 差异对比界面
为了支持交互式代码修改,插件可以提供一个差异对比界面。这使得 CLI 能够请求 IDE 打开一个差异视图,展示对文件的建议更改。用户随后可以在 IDE 内直接审查、编辑,并最终接受或拒绝这些更改。
openDiff 工具
插件必须在其 MCP 服务器上注册一个 openDiff 工具。
-
描述: 此工具用于指示 IDE 为特定文件打开可修改的差异视图。
-
请求(
OpenDiffRequest): 该工具通过tools/call请求调用。请求参数中的arguments字段必须是一个OpenDiffRequest对象。interface OpenDiffRequest { // 要进行差异比较的文件的绝对路径。 filePath: string; // 文件的新内容建议。 newContent: string; } -
响应(
CallToolResult): 工具必须立即返回一个CallToolResult以确认请求,并报告是否成功打开了差异视图。- 成功时:如果差异视图成功打开,响应必须包含空内容(即
content: [])。 - 失败时:如果错误导致无法打开差异视图,响应必须设置
isError: true,并在content数组中包含一个描述错误的TextContent块。
差异的实际结果(接受或拒绝)将通过通知异步传达。
- 成功时:如果差异视图成功打开,响应必须包含空内容(即
closeDiff 工具
插件必须在其 MCP 服务器上注册一个 closeDiff 工具。
-
描述: 此工具用于指示 IDE 关闭特定文件的打开差异视图。
-
请求(
CloseDiffRequest): 该工具通过tools/call请求调用。请求参数中的arguments字段必须是一个CloseDiffRequest对象。interface CloseDiffRequest { // 应关闭其差异视图的文件的绝对路径。 filePath: string; } -
响应(
CallToolResult): 该工具必须返回一个CallToolResult。- 成功时:如果差异视图成功关闭,响应必须在内容数组中包含一个 TextContent 块,其中包含关闭前文件的最终内容。
- 失败时:如果错误导致无法关闭差异视图,响应必须设置
isError: true,并在content数组中包含一个描述错误的TextContent块。
ide/diffAccepted 通知
当用户接受差异视图中的更改(例如,通过点击“应用”或“保存”按钮)时,插件必须向 CLI 发送 ide/diffAccepted 通知。
-
负载: 通知参数必须包含文件路径和文件的最终内容。如果用户在差异视图中进行了手动编辑,该内容可能与原始的
newContent不同。{ // 已进行差异比较的文件的绝对路径。 filePath: string; // 接受更改后的文件完整内容。 content: string; }
ide/diffRejected 通知
当用户拒绝更改(例如,关闭差异视图而不接受更改)时,插件必须向 CLI 发送 ide/diffRejected 通知。
-
负载: 通知参数必须包含被拒绝差异的文件路径。
{ // 已进行差异比较的文件的绝对路径。 filePath: string; }
IV. 生命周期接口
插件必须根据 IDE 的生命周期正确管理其资源和发现文件。
- 激活时(IDE 启动/插件启用):
- 启动 MCP 服务器。
- 创建发现文件。
- 停用时(IDE 关闭/插件禁用):
- 停止 MCP 服务器。
- 删除发现文件。