摘要:GitHub 已经把基于 GitHub App 的 Copilot Extensions 全面下线,官方指定替代方案是 MCP(Model Context Protocol)服务器。这篇文章复盘一次真实迁移:从旧 Extension 的 API 面改成 MCP server,中间踩了认证、工具命名、流式响应三个坑,最后给出可复用的迁移清单。适合正在维护 Copilot 集成、或者想搞清楚 MCP 到底怎么接的后端开发者。
1. 背景与痛点
事情要从一封告警邮件说起。
上周三早上,我们的内部 Copilot 集成突然集体 404。翻了半天日志没头绪,最后在 GitHub Changelog 里找到了答案:基于 GitHub App 的 Copilot Extensions 已于 2025 年 11 月 10 日 23:59(PST)全面停用。
官方时间线是这样的(来源:github.blog/changelog/2025-09-24):
- 2025 年 9 月 24 日:停止新建服务端 Extension
- 2025 年 11 月 3 日至 7 日:brownout 测试期,服务间歇性中断
- 2025 年 11 月 10 日:全部 Copilot Extensions 停用
要注意的是,这次下线只影响服务端 Extension(挂载在 GitHub App 上的那种)。VS Code 客户端扩展和不含 Copilot Extension 功能的标准 GitHub App 都不受影响。我们中招,是因为内部工具走的是服务端路线。
GitHub 给的出路只有一个:迁移到 MCP。也就是从"给 Copilot 专供的私有协议"换成"一次构建、到处挂载"的开放标准。这件事对 .NET 和 Python 开发者影响最直接——集成的骨架要重写。
2. 技术原理:旧 Extension 和 MCP 差在哪
先把两种架构摆在一起看。
旧 Copilot Extension 的本质是一个 GitHub App:GitHub 把用户消息以 webhook 形式推到你的服务端,你返回特定格式的响应。认证走 GitHub App 的 token 体系,能力发现靠 Extension 的私有约定。
MCP 的思路完全不同:你的工具是一个独立的 MCP server,宿主(Copilot、Claude Code、其他任何兼容 agent)通过 JSON-RPC 与它握手,动态发现工具列表,调用时传结构化参数。宿主和工具之间是标准的客户端-服务器关系,GitHub 只是把 Copilot 变成了众多 MCP 宿主之一。
flowchart LR
subgraph 旧架构["旧:Copilot Extension(已停用)"]
| A1[Copilot 宿主] -->|webhook 私有协议| B1[GitHub App 服务端] |
end
subgraph 新架构["新:MCP Server"]
| A2[Copilot / VS Code] -->|JSON-RPC 握手| B2[MCP Server] |
| A3[Claude Code 等其他宿主] -->|同一套协议| B2 |
end
关键差别有三点:
- 认证归属:旧模式由 GitHub App 托管用户身份;MCP 模式下认证是 server 自己的事(OAuth 2.1 或 API key),宿主只负责传递。
- 能力发现:旧模式靠注册时的静态配置;MCP 用
tools/list动态发现。 - 可移植性:旧 Extension 只能挂在 Copilot 上;同一个 MCP server 可以同时被 Claude Code、VS Code Copilot 模式等多个宿主调用。这是这次迁移唯一的补偿——不再押注单一平台。
3. 环境准备
实测版本(2026 年 9 月):
- Python 3.12.6
- mcp SDK:
mcp==1.9.4(pip install "mcp[cli]") - 测试宿主:VS Code 1.96 + GitHub Copilot Chat(MCP 支持已内置)
- Claude Code 2.x(用来做跨宿主验证)
建议先去 GitHub MCP Registry(github.com/github/github-mcp-server 相关生态页)逛一圈,很多常见场景(issue 管理、仓库操作)已经有现成 server,不一定需要自己写。确认没有现成的再动手。
4. 实战实现:把一个旧 Extension 改写成 MCP Server
旧 Extension 里我们有一个工具:查询内部发布系统里某个服务的当前版本。旧实现是接 webhook、解析用户自然语言、查库、拼响应。迁移时不要复用"解析自然语言"那部分——MCP 宿主自己会做意图映射,你的 server 只需要提供干净的、参数明确的工具。
用官方 Python SDK 重写:
# server.py
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("deploy-info")
@mcp.tool()
def get_service_version(service_name: str, env: str = "prod") -> dict:
"""查询指定服务在某个环境的当前版本。
Args:
service_name: 服务名,如 "gateway"
env: 环境名,prod / staging / dev
"""
# 这里替换成你真实的查询逻辑
return {
"service": service_name,
"env": env,
"version": "2.14.3",
"deployed_at": "2026-09-24T03:12:00Z",
}
if __name__ == "__main__":
mcp.run() # 默认 stdio 传输
然后在 VS Code 的 mcp.json 里注册:
{
"servers": {
"deploy-info": {
"command": "python3",
"args": ["/opt/tools/deploy-mcp/server.py"]
}
}
}
重启 VS Code,在 Copilot Chat 里输入"@deploy-info gateway 现在是什么版本",宿主会自动发现并调用 get_service_version。全程不需要你写任何自然语言解析。
5. 效果验证
迁移前后对比(同一功能,内部实测):
| 对比项 | 旧 Copilot Extension | MCP Server |
|---|---|---|
| 接入协议 | webhook + 私有响应格式 | JSON-RPC,标准协议 |
| 可用宿主 | 仅 Copilot | Copilot、Claude Code、其他 MCP 宿主 |
| 认证方式 | GitHub App 托管 | server 自管(OAuth 2.1 / key) |
| 意图解析 | 服务端自己写 | 宿主负责 |
| 部署形态 | 必须公网可达 | stdio 本地进程或远程均可 |
| 迁移工作量 | — | 约 3 人日/工具 |
跨宿主验证很重要。我们在 Claude Code 里挂同一个 server,零改动直接跑通——这是旧架构做不到的。
6. 踩坑记录
坑一:认证自己扛。 旧 Extension 的用户身份由 GitHub App 透传,MCP server 的认证完全自理。内部工具一开始图省事用了裸 API key,code review 被打回来。远程 MCP server 的规范推荐 OAuth 2.1 授权码流程,SDK 里有现成的 provider 接口,照着实现即可,别自己发明。
坑二:工具描述就是提示词。 第一版我把 docstring 写成了"查询版本",结果宿主在很多问法下不触发这个工具。MCP 宿主靠工具的 name + description + 参数 schema 来决定何时调用,description 要写成给模型看的触发条件,把常见问法变体覆盖进去。改完描述后触发率明显上升。这是整个迁移里性价比最高的一次修改。
坑三:stdio 下的日志会毁掉协议。 调试时习惯性地往 stdout 打日志,宿主直接解析失败断连——stdio 传输下 stdout 是协议通道,日志必须走 stderr。官方文档写得很"清楚"(指我第一次没读到),建议一开始就用 logging 模块配置 stderr handler。
坑四:混合 App 要手动拆配置。 如果你的 GitHub App 既是标准 App 又开了 Extension 功能,必须在停用前手动关掉 Extension 配置,否则连 Marketplace 上架状态都会受影响。我们有个边缘工具就是这种混合形态,差点被连坐。
7. 总结与展望
这次迁移本质上是一次"去专有化":GitHub 把私有扩展机制换成了开放标准,短期是返工,长期换来跨宿主可移植性。给还在观望的人三个建议:先查 MCP Registry 有没有现成的;工具描述当提示词认真写;远程 server 尽早把 OAuth 补上。
你的团队迁移 MCP 了吗?是直接用官方 GitHub MCP Server,还是自建?工具命名和权限控制上踩过什么坑,评论区聊聊,我整理进下一篇。
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/weixin_55357163/article/details/166638137




