最近市面上出现了不少”Copilot 增强”付费插件(比如 Copilot Enhance Tool),号称能让 Copilot 变得更强:结构化对话、自动检查点、子代理协作、还能省 premium requests。

我把它的 .vsix 拆了一遍,发现核心原理就是 tool call 循环 + 自定义 instructions + Agent 提示词。这些能力 Copilot 原生全部具备,配合一个轻量的 MCP Server + 独立网页面板就能完整复刻。

付费插件到底做了什么

拆包分析后(4.8MB 混淆代码,全局变量名都是 _0x 开头),架构其实很清晰:

┌────────────────────────────────────┐
│  VS Code Copilot Chat              │
│  ↕ (MCP 协议, stdio)               │
│  本地 MCP Server                   │
│  ↕ (HTTP)                          │
│  WebView 控制面板(反馈/选项/队列) │
└────────────────────────────────────┘

四个核心机制:

机制插件做了什么替代方案
MCP Server注册 copilot_enhance_{port} 工具,AI 通过 tool call 暂停等反馈自建 MCP Server,200 行
控制面板WebView 嵌入 VS Code,提供输入框和选项按钮HTTP 网页,VS Code Simple Browser 打开
自定义指令写入 .github/copilot-instructions.md原生支持,直接建文件
子代理安装 .github/prompts/*.prompt.mdVS Code 原生 Prompt Files

它注入的”开头语”(从混淆代码中提取):

在后续的持续协作中,启用协作工作流。工具列表中名称包含 copilot_enhance_{port} 的协议同步工具作为唯一的交流节点;每轮通过协议同步工具向我汇报结果或询问下一步,而非以文字输出收尾。

翻译一下:让 AI 每次回复都 call 一个 MCP tool,通过 tool 的 input/output 实现结构化对话,而不是直接输出文字。

省钱的秘密:tool call 循环

这是付费插件最吸引人的卖点之一。

Copilot 怎么计费

GitHub Copilot 按用户发起的请求数计费(premium requests),具体机制可以参考 之前的分析。简单说:你每发一条消息,算一次 premium request × 模型倍率。但 AI 调用工具(tool call)不算新请求,它属于同一个 request 的 agent loop。

插件的做法

你发 1 条消息 → AI 处理 → 调 MCP tool(暂停,等你在 WebView 输入)
→ 你在输入框打字提交 → 作为 tool response 返回 → AI 继续处理
→ 再调 MCP tool → 你再输入 → ...循环

整个过程都在同一个 request 里。AI 始终没有”结束回复”,它一直在 tool call 循环里。不管来回交互多少轮,计费只算开头那 1 次。

为什么单靠 instructions 做不到

你可能想:直接在 instructions 里写”每步用 ask_user 汇报”不就行了?

实测结论:instructions 是建议,不是强制约束。 AI 读到了但会自主判断要不要遵守——简单任务它会直接回答,跳过 ask_user。tool call 循环一断,下一轮对话就又算一次新请求。

要可靠触发每轮都走 tool call,需要一个 MCP Server 作为强制锚点。instructions 负责告诉 AI “必须调用 sync 工具”,MCP Server 负责接住这个调用并等你的反馈。两层配合才能稳定工作。


动手:完整复刻方案

整体方案需要这几个文件:

~/.copilot/mcp-servers/workflow-sync.mjs  ← MCP Server(~180 行)
~/.copilot/mcp-servers/panel.html         ← 网页控制面板(Tailwind CSS)
~/.copilot/mcp-config.json                ← Copilot CLI 全局 MCP 配置
.github/copilot-instructions.md 自定义指令
.vscode/mcp.json VS Code MCP 配置(可选)
.github/prompts/*.prompt.md Agent 提示词(可选)

Step 1:写 MCP Server

核心组件。架构:一个 stdio MCP Server + 一个独立 HTML 控制面板。MCP 通过 stdio 跟 Copilot 通信,HTTP 端口提供网页给你操作——等价于付费插件的 WebView。

面板采用 Tailwind CDN 做布局样式,CSS 变量做主题切换,历史消息用聊天气泡风格展示。HTML 从 JS 中拆分为独立文件,消除了模板字符串的转义 bug,也方便单独迭代 UI。

功能:

功能说明
进度汇报AI 每步调用 sync 工具,面板实时显示摘要
指令输入输入框 + 回车发送
消息队列AI 工作时提前排多条指令,sync 时自动取下一条,支持拖拽排序
收藏指令保存常用指令(短名 + 完整内容),一键发送,localStorage 持久化
交互历史实时滚动展示完整的汇报和指令记录
桌面通知等待指令时弹浏览器通知,可以放心切窗口
主题切换Light / Dark / Midnight 三套主题,一键切换,记住选择
多实例管理多个 CLI 自动分配端口,单页面管理所有实例
分屏 / 标签切换split 并排显示(可拖拽调整宽度)或 tabs 单面板切换
实例命名双击标签重命名,标识每个实例的用途
状态指示灯绿色=工作中,蓝色=等待输入

创建目录并安装依赖:

mkdir -p ~/.copilot/mcp-servers
cd ~/.copilot/mcp-servers
npm init -y
npm install @modelcontextprotocol/sdk zod
# 确保 package.json 有 "type": "module"

创建 ~/.copilot/mcp-servers/workflow-sync.mjs(Server 端约 180 行,UI 在独立的 panel.html 中):

#!/usr/bin/env node
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import http from "http";
import { readFileSync } from "fs";
import { fileURLToPath } from "url";
import { dirname, join } from "path";
 
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const panelPath = join(__dirname, 'panel.html');
 
const BASE_PORT = 3210;
let pendingResolve = null;
let lastReport = { summary: "等待 AI 连接...", questions: "", options: [] };
const history = [];  // { role: "ai"|"user", text, ts }
const queue = [];    // 用户预输入队列
 
// HTTP Server: 提供网页控制面板 + API
const httpServer = http.createServer((req, res) => {
  if (req.url === "/") {
    // 每次请求读取文件,开发时改 panel.html 刷新即可
    const html = readFileSync(panelPath, 'utf8');
    res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
    res.end(html);
  }
  if (req.url === "/status") { /* 返回当前状态 + 历史 + 队列 */ }
  if (req.url === "/feedback") { /* 用户输入:pending 时直接发,否则入队 */ }
  if (req.url === "/queue/remove") { /* 从队列中删除指定项 */ }
  if (req.url === "/queue/move") { /* 拖拽排序:调整队列顺序 */ }
});
 
// MCP Server: 注册 sync 工具
const server = new McpServer({ name: "workflow-sync", version: "1.0.0" });
 
server.tool("sync", "汇报进度并等待用户指令", {
  summary: z.string(),
  questions: z.string().optional(),
  options: z.array(z.string()).optional(),
}, async ({ summary, questions, options }) => {
  lastReport = { summary, questions: questions || "", options: options || [] };
  history.push({ role: "ai", text: summary, ts: now() });
 
  // 队列有内容 → 立即返回,不等用户
  if (queue.length > 0) {
    const next = queue.shift();
    history.push({ role: "user", text: next, ts: now() });
    return { content: [{ type: "text", text: next }] };
  }
  // 队列为空 → 阻塞等待用户在网页上输入
  const feedback = await new Promise(r => { pendingResolve = r; });
  return { content: [{ type: "text", text: feedback }] };
});
 
await server.connect(new StdioServerTransport());

面板的主题切换通过 CSS 变量 + Tailwind CDN 实现。三套主题通过 data-theme 属性控制颜色变量,Tailwind 负责布局和排版:

<!-- Tailwind CDN + 自定义色彩映射 -->
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
  theme: { extend: { colors: {
    surface: { DEFAULT: 'var(--bg)', card: 'var(--card)' },
    content: { DEFAULT: 'var(--text)', secondary: 'var(--text2)', muted: 'var(--text3)' },
    accent: { DEFAULT: 'var(--accent)', hover: 'var(--accent-hover)' },
    edge: 'var(--border)',
  }}}
}
</script>
/* CSS 变量定义主题色 */
:root { --bg: #fafafa; --card: #fff; --accent: #2563eb; ... }
[data-theme="dark"] { --bg: #0a0a0a; --card: #161616; --accent: #3b82f6; ... }
[data-theme="midnight"] { --bg: #0c0f1a; --card: #141929; --accent: #7c3aed; ... }

然后就能用 Tailwind 类名引用主题色:bg-surfacetext-contentborder-edgebg-accent。切换主题只改 CSS 变量,Tailwind 类名不用变。

历史消息用聊天气泡展示(借鉴 chatbot-ui-lite 的设计):

<!-- AI 消息左对齐 -->
<div class="flex flex-col items-start">
  <div class="bg-surface-ai rounded-2xl px-3 py-1.5 max-w-[85%]">...</div>
</div>
<!-- 用户消息右对齐 -->
<div class="flex flex-col items-end">
  <div class="bg-surface-user rounded-2xl px-3 py-1.5 max-w-[85%]">...</div>
</div>

输入框用自动增高的 textarea,支持 Shift+Enter 换行,Send 按钮是圆形箭头图标:

<div class="relative">
  <textarea class="w-full rounded-lg border-2 border-edge pl-3 pr-10 py-2.5"
    style="resize:none;field-sizing:content;min-height:36px;max-height:120px"></textarea>
  <button class="absolute right-2 bottom-2 w-7 h-7 rounded-full bg-accent text-white">
    <svg><!-- arrow up icon --></svg>
  </button>
</div>

上面是精简版,省略了路由细节和面板 HTML。完整源码分两个文件:workflow-sync.mjs(~180 行 Server)和 panel.html(~550 行 UI)。

📦 下载源码workflow-sync.zip(全部文件) | 或单独下载:install.sh(一键安装)

关键设计点:

消息队列:AI 工作时(pendingResolve === null),你在面板输入的内容不会丢失,而是进入 queue 数组。AI 下次调 sync 时先检查队列,有就直接取出返回,不需要等你再输入一次。你可以一口气排好接下来几步的指令,AI 会按顺序执行。队列内的项目支持拖拽排序——按住就能拖动调整优先级,也可以随时删除不需要的指令。

收藏指令:面板支持把常用指令保存为收藏。每条收藏有两个字段:显示名(简短,方便辨认)和完整内容(可以是长 prompt)。点击收藏按钮,完整内容自动发送。收藏数据存在浏览器 localStorage 里,不占服务端资源,重启不丢失。

浏览器通知:面板首次打开时请求通知权限。AI 从”工作中”变为”等待指令”时自动弹桌面通知。切到别的窗口写文档或看代码都不会错过。

主题切换:面板右上角提供三个色块按钮,分别对应 Light、Dark、Midnight 三套主题。点击即切换,选择记录在 localStorage。如果没有手动选择,默认跟随系统的深色/浅色设置。CSS 变量定义颜色,Tailwind 类名引用变量——切主题时只变变量值,Tailwind 类名保持不变。

  • Light:白底蓝色高亮,适合白天
  • Dark:纯黑底灰白文字,经典暗色
  • Midnight:深蓝底紫色高亮,写代码时视觉疲劳最小

文件拆分:HTML 面板从 Server 代码中拆分为独立的 panel.html。Server 每次请求时 readFileSync 读取文件,开发时修改面板刷新浏览器即可看到效果,不需要重启 MCP Server。彻底消除了之前在 JS 模板字符串中嵌套 HTML/JS 导致的 \n 转义 bug。

多实例管理:同时开多个 Copilot CLI 实例时,每个实例的 MCP Server 自动寻找可用端口(3210、3211、3212…)。面板在客户端用 JS 扫描 localhost:3210-3219,发现所有存活实例,显示为标签页。

两种视图模式:

  • tabs 模式(默认):单面板,点击标签切换实例
  • split 模式:所有实例并排显示,中间有可拖拽分隔线调整宽度

标签支持双击重命名,比如叫”重构 auth”或”跑测试”。名称存在 localStorage,关掉再打开还在。

状态指示灯逻辑:

  • 绿色 = 工作中
  • 橙色闪烁 = 当前面板等待输入
  • 蓝色常亮 = 其他面板等待输入(提醒你去看,不打扰)

自动端口分配的实现:

function tryListen(server, port, maxTries = 10) {
  return new Promise((resolve, reject) => {
    let tries = 0;
    function attempt(p) {
      server.once('error', (err) => {
        if (err.code === 'EADDRINUSE' && tries < maxTries) {
          tries++;
          attempt(p + 1);
        } else reject(err);
      });
      server.listen(p, () => resolve(p));
    }
    attempt(port);
  });
}

客户端发现逻辑:

// 每 2.5 秒扫描端口范围
function discover() {
  for (var p = 3210; p < 3220; p++) {
    fetch('http://localhost:'+p+'/status', { signal: AbortSignal.timeout(600) })
      .then(r => r.json())
      .then(d => { instances[p] = { data: d, pending: d.pending }; renderTabs(); })
      .catch(() => { delete instances[p]; renderTabs(); });
  }
}

数据流:

AI 调用 sync(summary="重构了 3 个文件")
 Server 更新 lastReport,记入 history
 检查 queue:有 直接返回队首内容;空 阻塞等待
 网页轮询 /status,显示进度,状态变为"等待指令"
 浏览器弹通知
 你在输入框打字 / 点收藏按钮 POST /feedback
 pendingResolve resolve 返回 tool response
 AI 继续工作

Step 2:配置 MCP

Copilot CLI 全局配置~/.copilot/mcp-config.json):

{
  "mcpServers": {
    "workflow-sync": {
      "type": "stdio",
      "command": "node",
      "args": ["/Users/你的用户名/.copilot/mcp-servers/workflow-sync.mjs"]
    }
  }
}

注意 Copilot CLI 用的 key 是 mcpServers,不是 servers,跟 VS Code 的格式不同。

每次启动 copilot 命令时会自动加载这个配置,spawn MCP Server 子进程。

VS Code 项目配置.vscode/mcp.json,可选):

{
  "servers": {
    "workflow-sync": {
      "type": "stdio",
      "command": "node",
      "args": ["/Users/你的用户名/.copilot/mcp-servers/workflow-sync.mjs"]
    }
  }
}

VS Code 打开这个文件后,每个 server 上方会出现启动按钮。点击启动后 Copilot Chat 也能使用 sync 工具。

两个配置指向同一个 Server 文件,但 key 名不同(CLI 用 mcpServers,VS Code 用 servers)。CLI 和 VS Code 各自 spawn 独立的实例,端口可能冲突。如果需要同时用,改一下其中一个的 PORT 变量。

Step 3:写自定义指令

创建 .github/copilot-instructions.md(项目级)或 ~/.copilot/copilot-instructions.md(全局):

## Task Execution
 
- Break complex tasks into steps; after each step, call the `sync` tool to report progress and wait for instructions
- Your final action in every turn must be a `sync` tool call — never end with plain text
- When the task is ambiguous, ask via `sync` before guessing
- For multi-file changes, report after each file
- Even after completing the task, call `sync` to ask "anything else?"
 
## Coding
 
- Explore code before modifying; check cross-file dependencies
- Fix root causes, not symptoms
- No unnecessary defensive code or redundant checks

这个文件的作用是强制 AI 每轮结束时调用 sync 工具。没有它,MCP Server 虽然启动了但 AI 不会主动调用——你得每次手动说”用 sync 汇报”。加上之后就是自动的了。

这就是付费插件写入 .github/copilot-instructions.md 的核心内容,只是工具名从 copilot_enhance_{port} 换成了 sync

Copilot CLI 和 VS Code Copilot Chat 都会自动读取这个文件。放项目级只对当前项目生效,放全局 ~/.copilot/copilot-instructions.md 则所有项目都生效。建议两个都放,确保覆盖。

Step 4:打开控制面板

在 VS Code 里打开(推荐,保持单窗口体验):

Cmd+Shift+PSimple Browser: Show → 输入 http://localhost:3210

终端面板跑 Copilot CLI(或 Copilot Chat),侧边面板是控制面板,全在一个窗口里。

也可以直接在浏览器打开 http://localhost:3210

控制面板三种状态:

  • AI 工作中 — 正在处理任务,你可以提前在输入框排指令
  • 等待指令 — AI 调用了 sync,等你输入
  • 已断开 — MCP Server 没启动或已退出

Step 5:配置 Agent 提示词(可选)

VS Code 原生支持 Prompt Files(.github/prompts/*.prompt.md),等同于付费插件的”子代理”。

创建 .github/prompts/plan.prompt.md

---
name: Plan
description: "研究驱动的交互式规划,不执行修改"
model: claude-sonnet-4
tools: [read, search]
---
 
你是规划专家。通过研究代码库 → 与用户对齐 → 输出详细计划。
 
## 规则
- 只规划不执行,绝不修改文件
- 先调研现有代码,再制定方案
- 每个阶段通过 sync 工具与用户确认后再继续
- 输出格式:步骤 → 涉及文件 → 验证方法 → 待确认问题

创建 .github/prompts/reviewer.prompt.md

---
name: Reviewer
description: "代码审查,只审不改"
model: claude-sonnet-4
tools: [read, search]
---
 
你是代码审查官。检查代码的正确性、完整性、一致性。
 
## 审查维度
1. 意图一致性:是否完整实现了目标?
2. 正确性:类型安全、接口兼容
3. 完整性:边界条件、错误处理
4. 副作用:是否影响无关功能
 
## 输出格式
| # | 严重度 | 位置 | 问题 | 建议 |
|---|--------|------|------|------|
 
只报告不修复。

在 Copilot Chat 中通过 @workspace /plan 规划认证模块重构 调用。


实际效果

配置完成后的交互流程:

你(在 Copilot CLI 或 Chat 里):帮我重构用户认证模块
 
AI:(分析代码...修改文件...)
    → 调用 sync(summary="分析了现有认证模块,计划分 3 步...")
 
控制面板显示:
  ┌────────────────────────────────────────┐
  │ ⚡ Workflow Sync  [:3210] [:3211] [◐◑◒]
  │                                        │
  │ ● Waiting for input                    │
  │ ┌── Current ────────────────────────┐  │
  │ │ 分析了现有认证模块,计划分 3 步:  │  │
  │ │ 1. 抽取 JWT 逻辑到独立模块        │  │
  │ │ 2. 统一错误处理                   │  │
  │ │ 3. 添加 refresh token 支持        │  │
  │ │ 方案是否需要调整?                │  │
  │ └───────────────────────────────────┘  │
  │                                        │
  │ ┌── History ────────────────────────┐  │
  │ │  AI · 12:30  分析了现有认证模块.. │  │
  │ │           You · 12:31  第2步先不做 │  │
  │ └───────────────────────────────────┘  │
  │                                        │
[继续] [跑测试] [Review] [+ add]
  │                                        │
  │ ┌──────────────────────────┐  [↑]
  │ │ 第 2 步先不做,先搞 13│          │
  │ └──────────────────────────┘          │
  │                                        │
  │ ┌── Queue (0) ──────── [clear] ────┐  │
  │ │ empty                             │  │
  │ └───────────────────────────────────┘  │
  └────────────────────────────────────────┘
 
你提交 → AI 继续 → 再调 sync → 你再反馈 → ...
 
全程 1 个 premium request

跟付费插件的对比:

维度付费插件本方案
控制面板VS Code WebView(内嵌)VS Code Simple Browser 或浏览器
省 premium requeststool call 循环同样的 tool call 循环
强制每轮触发system prompt 注入MCP tool + instructions
消息队列有,拖拽排序,自动按顺序执行
交互历史有,实时滚动展示
桌面通知WebView 内通知浏览器 Notification API
收藏指令按钮自定义收藏(短名 + 完整内容)
主题Light / Dark / Midnight 三选一
多实例单实例自动端口分配,单页面管理,分屏/标签切换
实例标识双击标签重命名 + 状态指示灯(绿/蓝)
代码量4.8MB 混淆~180 行 Server + ~550 行 UI
价格付费免费
透明度混淆完全透明

付费插件多出来的功能

公平起见,列一下付费插件有而本方案暂时不包含的:

功能替代方案难度
代码检查点/快照git stash / git tag / VS Code Timeline
图片粘贴发送Copilot Chat 原生支持 #image
会话记录管理Copilot Chat 有历史;CLI 可 tee 到文件
子代理委托VS Code 原生 Prompt Files + Agent mode

核心功能(结构化对话 + 省请求)完全复刻,其余用 git 等现有工具就够了。


附录:Copilot CLI 的 MCP 配置参考

# 全局配置文件(推荐)
# ~/.copilot/mcp-config.json — 每次 copilot 启动自动加载
 
# 临时追加 MCP Server(不覆盖全局配置,可多次使用)
copilot --additional-mcp-config @./my-server-config.json
 
# 禁用内置的 GitHub MCP Server(省资源)
copilot --disable-builtin-mcps
 
# 禁用特定 MCP Server
copilot --disable-mcp-server workflow-sync
 
# 进入交互模式后查看已连接的 MCP Server
# 输入 /mcp

Copilot CLI 读取指令文件的优先级(从高到低):

  • 项目级:.github/copilot-instructions.mdCLAUDE.mdAGENTS.md
  • 目录级:.github/instructions/**/*.instructions.md(可按路径匹配生效范围)
  • 全局级:~/.copilot/copilot-instructions.md

写在最后

付费插件把 MCP Server、instructions、prompts 打包成一个付费产品。拆开来看,核心技术全是 Copilot 原生支持的标准协议。它的价值在于产品化包装——开箱即用、不用折腾配置。

但如果你愿意花 10 分钟配置,~180 行 Server + ~550 行 UI(独立 HTML 文件,Tailwind CSS)就能完整复刻核心功能(包括消息队列、收藏指令、聊天气泡历史、桌面通知、主题切换、多实例分屏管理),而且你完全知道它在干什么——没有 4.8MB 的混淆代码,没有发送 machineId 到远程服务器,没有卡密验证系统。

值得学习的是它的设计思路:

  1. tool call 循环 — 通过 MCP 工具调用暂停而非结束回复,多轮交互只算一次请求
  2. 角色分离 — 不同任务用不同 Agent 提示词,各司其职
  3. 指令驱动 — 用 instructions 约束 AI 行为,而不是靠 AI 自觉

这些思路不需要任何付费插件。