Gemini CLI Companion Plugin: Interface Specification
最后更新:2025 年 9 月 15 日
此文档定义了用于构建 Gemini CLI IDE 模式的伴侣插件的契约。对于 VS Code,这些功能(原生 diffing、上下文感知)由官方扩展(marketplace)提供。本规范适用于希望将类似功能引入 JetBrains IDE、Sublime Text 等其他编辑器的贡献者。
I. 通信接口
Gemini CLI 和 IDE 插件通过本地通信通道进行通信。
1. 传输层:HTTP 上的 MCP
插件 必须 运行一个实现 模型上下文协议 (MCP) 的本地 HTTP 服务器。
- 协议: 服务器必须是一个有效的 MCP 服务器。如果可用,我们建议使用您所选语言的现有 MCP SDK。
- 端点: 服务器应公开一个用于所有 MCP 通信的单个端点(例如
/mcp)。 - 端口: 服务器 必须 监听动态分配的端口(即监听端口
0)。
2. 发现机制:端口文件
为了让 Gemini CLI 连接,它需要发现它正在运行的 IDE 实例以及您的服务器正在使用的端口。插件 必须 通过创建“发现文件”来促进这一点。
CLI 如何查找文件: CLI 通过遍历进程树来确定其正在运行的 IDE 的进程 ID (PID)。然后,它会查找一个文件名包含该 PID 的发现文件。
文件位置: 文件必须创建在特定目录中:
os.tmpdir()/gemini/ide/。如果该目录不存在,您的插件必须创建它。文件名约定: 文件名至关重要,必须 遵循以下模式:
gemini-ide-server-${PID}-${PORT}.json${PID}:父 IDE 进程的进程 ID。您的插件必须确定此 PID 并将其包含在文件名中。${PORT}:您的 MCP 服务器正在监听的端口。
文件内容和工作区验证: 文件 必须 包含一个具有以下结构的 JSON 对象:
json{ "port": 12345, "workspacePath": "/path/to/project1:/path/to/project2", "authToken": "a-very-secret-token", "ideInfo": { "name": "vscode", "displayName": "VS Code" } }port(number, required):MCP 服务器的端口。workspacePath(string, required):所有打开的工作区根路径的列表,由操作系统特定的路径分隔符(Linux/macOS 为:,Windows 为;)分隔。CLI 使用此路径来确保它正在与 IDE 中打开的同一项目文件夹运行。如果 CLI 的当前工作目录不是workspacePath的子目录,则连接将被拒绝。您的插件 必须 提供打开的工作区根目录的正确绝对路径。authToken(string, required):用于保护连接的密钥令牌。CLI 将在所有请求中将此令牌包含在Authorization: Bearer <token>标头中。ideInfo(object, required):有关 IDE 的信息。name(string, required):IDE 的简短小写标识符(例如vscode、jetbrains)。displayName(string, required):IDE 的用户友好名称(例如VS Code、JetBrains IDE)。
身份验证: 为了保护连接,插件 必须 生成一个唯一的密钥令牌,并将其包含在发现文件中。然后,CLI 将在所有发往 MCP 服务器的请求中将此令牌包含在
Authorization标头中(例如Authorization: Bearer a-very-secret-token)。您的服务器 必须 在每个请求上验证此令牌,并拒绝任何未经授权的请求。与环境变量的冲突解决(推荐): 为了获得最可靠的体验,您的插件 应该 同时创建发现文件并在集成终端中设置
GEMINI_CLI_IDE_SERVER_PORT环境变量。该文件作为主要的发现机制,但环境变量对于冲突解决至关重要。如果用户为同一工作区打开了多个 IDE 窗口,CLI 会使用GEMINI_CLI_IDE_SERVER_PORT变量来识别并连接到正确的窗口服务器。
II. 上下文接口
为了实现上下文感知,插件 可以 向 CLI 提供有关用户在 IDE 中活动的实时信息。
ide/contextUpdate 通知
每当用户上下文发生变化时,插件 可以 向 CLI 发送 ide/contextUpdate 通知。
触发事件: 应在以下情况发送此通知(建议去抖动时间为 50ms):
- 文件被打开、关闭或获得焦点。
- 活动文件中的用户光标位置或文本选择发生更改。
载荷 (
IdeContext): 通知参数 必须 是一个IdeContext对象:typescriptinterface 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. Diffing 接口
为了实现交互式代码修改,插件 可以 公开一个 diffing 接口。这允许 CLI 请求 IDE 打开一个 diff 视图,显示文件的建议更改。然后,用户可以直接在 IDE 中查看、编辑并最终接受或拒绝这些更改。
openDiff 工具
插件 必须 在其 MCP 服务器上注册一个 openDiff 工具。
描述: 此工具指示 IDE 为特定文件打开一个可修改的 diff 视图。
请求 (
OpenDiffRequest): 通过tools/call请求调用此工具。请求params中的arguments字段 必须 是一个OpenDiffRequest对象。typescriptinterface OpenDiffRequest { // 要进行 diff 的文件的绝对路径。 filePath: string; // 文件的建议新内容。 newContent: string; }响应 (
CallToolResult): 工具 必须 立即返回一个CallToolResult以确认请求并报告 diff 视图是否已成功打开。- 成功时:如果 diff 视图已成功打开,响应 必须 包含空内容(即
content: [])。 - 失败时:如果错误阻止了 diff 视图的打开,响应 必须 设置
isError: true,并在content数组中包含一个描述错误的TextContent块。
diff 的实际结果(接受或拒绝)通过通知异步传达。
- 成功时:如果 diff 视图已成功打开,响应 必须 包含空内容(即
closeDiff 工具
插件 必须 在其 MCP 服务器上注册一个 closeDiff 工具。
描述: 此工具指示 IDE 关闭特定文件的打开 diff 视图。
请求 (
CloseDiffRequest): 通过tools/call请求调用此工具。请求params中的arguments字段 必须 是一个CloseDiffRequest对象。typescriptinterface CloseDiffRequest { // 应关闭 diff 视图的文件的绝对路径。 filePath: string; }响应 (
CallToolResult): 工具 必须 返回一个CallToolResult。- 成功时:如果 diff 视图已成功关闭,响应 必须 在 content 数组中包含一个单独的 TextContent 块,其中包含关闭前文件的最终内容。
- 失败时:如果错误阻止了 diff 视图的关闭,响应 必须 设置
isError: true,并在content数组中包含一个描述错误的TextContent块。
ide/diffAccepted 通知
当用户接受 diff 视图中的更改时(例如,通过单击“应用”或“保存”按钮),插件 必须 向 CLI 发送 ide/diffAccepted 通知。
载荷: 通知参数 必须 包含文件的路径和文件的最终内容。如果用户在 diff 视图中进行了手动编辑,则内容可能与原始
newContent不同。typescript{ // 已进行 diff 的文件的绝对路径。 filePath: string; // 接受后的文件的完整内容。 content: string; }
ide/diffRejected 通知
当用户拒绝更改时(例如,通过在未接受的情况下关闭 diff 视图),插件 必须 向 CLI 发送 ide/diffRejected 通知。
载荷: 通知参数 必须 包含已进行 diff 的文件的路径。
typescript{ // 已进行 diff 的文件的绝对路径。 filePath: string; }
IV. 生命周期接口
插件 必须 根据 IDE 的生命周期正确管理其资源和发现文件。
- 激活时(IDE 启动/插件启用):
- 启动 MCP 服务器。
- 创建发现文件。
- 停用时(IDE 关闭/插件禁用):
- 停止 MCP 服务器。
- 删除发现文件。