首页
/ Gemini CLI 接入 MCP 服务器实战:以 GitHub MCP Server 为例打通外部服务

Gemini CLI 接入 MCP 服务器实战:以 GitHub MCP Server 为例打通外部服务

2026-09-04 18:21:40作者:毕习沙Eudora

本文以 Gemini CLI 官方教程 docs/cli/tutorials/mcp-setup.md 为主线,带你从零完成一次完整的 MCP(Model Context Protocol)服务器接入:准备 GitHub 凭据、在 settings.json 中通过 Docker 方式配置 GitHub MCP Server、用 /mcp 命令验证连接,并直接用自然语言驱动 GitHub 工具。读完本篇,你不仅能复现教程中的全部操作步骤,还能结合源码理解 Gemini CLI 的传输选择、超时控制、工具命名与状态机等底层机制,从而具备排查任意 MCP 服务器连接问题的能力。

一、MCP 服务器是什么,为什么需要它

MCP 服务器是一个通过 Model Context Protocol 向 Gemini CLI 暴露工具(tools)、提示词(prompts)和资源(resources)的应用。它相当于模型与外部世界之间的桥梁:

  • 发现工具:通过标准化的 JSON Schema 定义列出可用工具及其参数;
  • 执行工具:用既定参数调用工具并拿到结构化响应;
  • 访问资源:读取服务器暴露的 URI 数据(文件、API 载荷、报告等)。

借助 MCP,Gemini CLI 的能力可以延伸到内置工具之外——例如操作 GitHub 仓库、查询数据库、调用任意 API。本教程选择 GitHub MCP Server 作为示例,因为它同时覆盖了三个最常见诉求:Docker 容器化部署、PAT 鉴权、自然语言驱动的外部写操作(创建 Issue、读取 PR)。

二、前置条件

在开始之前,确认以下环境已就绪:

  1. 已安装 Gemini CLI(可执行 gemini 命令进入交互式界面);
  2. Docker:本教程的 GitHub MCP Server 以 Docker 容器方式运行,因此宿主机必须安装并正在运行 Docker;
  3. GitHub 个人访问令牌(PAT):一个具备 repo 权限的 PAT,具体权限范围见下一节。

三、准备凭据:创建 GitHub PAT

大多数 MCP 服务器都需要鉴权,GitHub 使用 PAT。按以下步骤创建:

  1. 在 GitHub 的 Fine-grained personal access tokens 页面创建一个细粒度 PAT(fine-grained PAT);
  2. 权限授予建议(最小化原则):
    • MetadataContents:只读(Read);
    • IssuesPull Requests:读写(Read/Write),本教程的"创建 Issue"场景依赖写权限;
  3. 将令牌存入环境变量,而不是写进配置文件:

macOS/Linux

export GITHUB_PERSONAL_ACCESS_TOKEN="github_pat_..."

Windows (PowerShell)

$env:GITHUB_PERSONAL_ACCESS_TOKEN="github_pat_..."

说明:这个环境变量名 GITHUB_PERSONAL_ACCESS_TOKEN 是 GitHub MCP Server 官方约定的变量名,Docker 容器内部通过它读取令牌。你只需保证宿主机环境里有这个名字的变量即可。

四、配置 Gemini CLI:mcpServers 块详解

Gemini CLI 通过在 settings.json 中声明 mcpServers 对象来获知有哪些 MCP 服务器。每个条目本质上是一条指令:"启动这个命令,然后跟它的标准输入/输出对话。"

4.1 完整配置示例(Docker + GitHub MCP Server)

打开 ~/.gemini/settings.json(用户级)或项目根目录下的 .gemini/settings.json(项目级),加入如下 mcpServers 块:

{
  "mcpServers": {
    "github": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "-e",
        "GITHUB_PERSONAL_ACCESS_TOKEN",
        "ghcr.io/github/github-mcp-server:latest"
      ],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_PERSONAL_ACCESS_TOKEN}"
      }
    }
  }
}

逐字段解读:

字段 作用
"command": "docker" 要启动的可执行命令,这里是 docker,说明该服务器走 Stdio 传输
"args": [...] 传给 docker 的参数:-i 保持 stdin 打开(Stdio 传输必需),--rm 退出后清理容器,-e GITHUB_PERSONAL_ACCESS_TOKEN 把宿主机同名变量注入容器
"env": { ... } 通过 ${GITHUB_PERSONAL_ACCESS_TOKEN} 在运行时从宿主机环境展开令牌值,避免把密钥硬编码进配置文件
服务器名 "github" 即配置键名,会进入工具的全限定名 mcp_github_*不要使用下划线命名服务器(见第六节)

关键设计点:令牌不落盘env 中的 ${VAR} 语法由 Gemini CLI 的环境变量展开器在启动服务器时解析。这一点在源码中有明确实现——packages/core/src/tools/mcp-client.ts 中通过 expandEnvVarsenv 值做变量展开,支持 POSIX 语法 $VAR / ${VAR}(全平台)与 Windows 语法 %VAR%

4.2 环境变量展开与环境净化(源码级补充)

从源码结构看,Gemini CLI 在启动 MCP 服务器进程时并非把宿主机的整个环境直接透传。packages/core/src/tools/mcp-client.ts 引用了 sanitizeEnvironment 做环境净化:像 GEMINI_API_KEYGOOGLE_API_KEY 这类核心密钥,以及匹配 *TOKEN**SECRET**PASSWORD**KEY**AUTH* 等模式的变量会被默认从基础环境中剔除,防止第三方 MCP 服务器意外读到你的敏感凭据。只有你在 env显式声明的变量才会传递给服务器——这正是本教程"先 export 再用 ${GITHUB_PERSONAL_ACCESS_TOKEN} 显式引用"写法的底层原因:显式声明即视为用户知情同意,会跳过自动脱敏。

4.3 替代方案:用 gemini mcp add 命令写入配置

除了手编 JSON,仓库源码(packages/cli/src/commands/mcp/add.ts)表明 Gemini CLI 提供了 gemini mcp add 子命令,等效地生成 mcpServers 条目:

# stdio 传输(默认):command + args + env
gemini mcp add github docker \
  -e GITHUB_PERSONAL_ACCESS_TOKEN='${GITHUB_PERSONAL_ACCESS_TOKEN}' \
  -- run -i --rm -e GITHUB_PERSONAL_ACCESS_TOKEN ghcr.io/github/github-mcp-server:latest

# 可选参数(来自 yargs 定义):
#   --scope <user|project>   写入用户级还是项目级 settings(默认 project)
#   --transport <stdio|sse|http>  传输类型(默认 stdio)
#   --header "K: V"          sse/http 传输的自定义请求头
#   --timeout <ms>           连接超时
#   --trust                  跳过所有工具调用确认
#   --include-tools / --exclude-tools   工具白/黑名单

注意 -- 之后的参数会原样作为服务器参数追加(源码中通过 populate-- 与 middleware 合并实现)。对于本教程的 Docker 场景,由于参数较多且含 -e 注入,手编 settings.json 的可读性更好,两种方式的最终产物完全一致。

五、验证连接:/mcp 命令族

重启 Gemini CLI 后,它会按配置自动启动并发现 MCP 服务器。在交互界面输入:

/mcp list

连接成功时应看到类似 ✓ github: docker ... - Connected 的状态输出。如果显示 Disconnected 或错误信息,先确认 Docker 守护进程在运行、PAT 有效。

packages/cli/src/ui/commands/mcpCommand.ts 可以看到,/mcp 实际是一个子命令集合,日常排障时都很有用:

命令 作用
/mcp/mcp list 列出全部服务器、连接状态、各服务器的工具/Prompt/资源、鉴权状态与错误信息;后面跟文本则作为服务器名过滤
/mcp desc 在 list 基础上附带工具描述
/mcp schema 进一步附带参数 Schema
/mcp reload(别名 refresh) 调用 McpClientManager.restart() 重启所有 MCP 服务器并重新发现工具,随后自动再执行一次 list
/mcp auth [name] 对需要 OAuth 的远程服务器发起认证(本教程的 Docker 方案不需要)
/mcp enable <name> [--session] / /mcp disable <name> [--session] 启用/禁用某服务器,受 mcp.allowed / mcp.excluded 全局策略约束,改完自动重启服务器

/mcp list 输出的"错误信息"字段来自 McpClientManager.getLastError(serverName)——即每个服务器最近一次连接/发现失败的原始报错,是排障的第一现场。

六、底层原理:Gemini CLI 如何连接并使用一个 MCP 服务器

理解这一节能让你在 Disconnected 时快速定位问题层。

6.1 传输选择逻辑

packages/core/src/tools/mcp-client.tsconnectToMcpServer() 按配置字段决定传输方式:

  • 配了 commandStdioClientTransport:spawn 子进程(本教程的 Docker 场景),走 stdin/stdout;
  • 配了 url → 先按 Streamable HTTP 尝试,失败则回退 SSEClientTransport(源码中对 HTTP 404/401 有明确的回退与 OAuth 分支);
  • 配了 httpUrl → 直接 StreamableHTTPClientTransport

默认请求超时为 MCP_DEFAULT_TIMEOUT_MSEC = 10 * 60 * 1000(10 分钟),可在每个服务器配置中用 timeout 覆盖。

6.2 状态机与发现流程

每个服务器有一个 MCPServerStatus 状态机:DISCONNECTED → CONNECTING → CONNECTED(失败回落到 DISCONNECTED,另有 BLOCKED / DISABLED 两个管理态)。连接成功后 McpClient.discoverInto() 依次做三件事:拉取 prompts、发现 tools、发现 resources,并注册进对应的全局注册表;如果三者全空,会抛出 "No prompts, tools, or resources found" 并断开。此外客户端会监听 tools/list_changed 等通知,服务器端工具变化时无需手动 /mcp reload 也能自动刷新(源码中带合批与 500ms 重试逻辑,防止服务器"先通知后就绪"的竞态)。

6.3 工具命名:为什么叫 mcp_github_list_pull_requests

所有 MCP 工具都会无条件加上完全限定名(FQN)前缀,格式为 mcp_{serverName}_{toolName}。这在 packages/core/src/tools/mcp-tool.ts(约 L595)中实现,并有 packages/core/src/tools/tool-registry.test.ts 等测试用例反复断言 mcp_${serverName}_${toolName} 的命名结果。因此教程中 Agent 调用的 mcp_github_list_pull_requests,正是"服务器名 github + 原始工具名 list_pull_requests"拼接而来。

由此产生一条重要的命名约束(与 Policy Engine 相关):服务器名不要含下划线。策略解析器按 mcp_ 之后的第一个下划线切分 FQN,my_server 这类命名会让通配规则静默失效。

6.4 工具调用与确认

模型选中某个 MCP 工具后,由 DiscoveredMCPTool 处理确认逻辑:配置里 trust: true 的服务器跳过所有确认;否则弹出对话框,可选"仅本次"、"始终允许该工具"、"始终允许该服务器"或取消。执行时用原始工具名调用服务器,返回结果拆成两部分:llmContent 供模型上下文使用,returnDisplay 以 Markdown 形式展示给用户。

七、使用新工具:自然语言驱动 GitHub

服务器连上后,Agent 就多了"GitHub 能力",无需学习任何特殊命令,直接用自然语言下达即可。

场景 1:列出 Pull Requests

Prompt: List the open PRs in the google/gemini-cli repository.

Agent 的行为链条:

  1. 识别出请求匹配 GitHub 工具;
  2. 调用 mcp_github_list_pull_requests
  3. 把返回数据整理后呈现给你。

场景 2:创建 Issue

Prompt: Create an issue in my repo titled "Bug: Login fails" with the description "See logs".

由于 PAT 授予了 Issues 的 Read/Write 权限,这一步会真正在仓库中创建 Issue——这也是最小化权限的重要示范:不需要给仓库完整的 admin 权限,只给实际用到的 Issues/PR 写权限。

八、故障排查(Troubleshooting)

症状 处理方法
服务器起不来 在终端手动执行 settings.json 里那条 docker 命令,看是否输出 "image not found" 等错误;确认 Docker 守护进程在跑、镜像可拉取
工具找不到 执行 /mcp reload(即 refresh)强制 CLI 重新向服务器查询其能力,源码层面等价于 mcpClientManager.restart() + geminiClient.setTools() + 斜杠命令重载
状态是 Disconnected 且 list 里有报错 /mcp list 的 error 字段会给出最近一次连接失败的原始错误;配合 --debug 启动 CLI(交互模式按 F12 打开调试控制台)查看传输层日志
工具列表比预期少 检查是否被 includeTools / excludeTools 过滤(excludeTools 优先),或全局 mcp.allowed / mcp.excluded 名单,或服务器被 /mcp disable 禁用
凭据未生效 确认环境变量已 export 到启动 CLI 的同一个 shellenv 中的 ${VAR} 在变量缺失时会展开为空字符串

补充一条来自源码的行为细节:服务器进程若不提供任何 tools/prompts/resources,连接会在发现阶段被关闭,状态回落 DISCONNECTED——所以"连上了但什么工具都没有"通常意味着服务器本身没注册工具,或注册名被过滤规则挡掉了。

九、总结与延伸阅读

回顾本教程完成的完整闭环:

  1. 凭据:细粒度 PAT + 宿主机环境变量,令牌不写入配置文件;
  2. 配置settings.jsonmcpServers.github 声明 Docker 启动命令与 ${VAR} 环境展开;
  3. 验证:重启 CLI 后 /mcp list 确认 Connected,失败时看 error 字段并手动跑 docker 命令;
  4. 使用:自然语言触发 mcp_github_list_pull_requests 等 FQN 工具;
  5. 维护/mcp reload/mcp enable/disable 管理服务器生命周期。

如果你想继续深入,建议阅读以下仓库内的配套文档:

  • MCP 服务器完整参考:三种传输(Stdio/SSE/Streamable HTTP)、OAuth 自动发现、authProviderType 各取值、headers、工具过滤、Schema 清洗与发现流程的深度剖析,以及远程服务器配置示例;
  • MCP 资源工具:用 @server://... 引用远程资源;
  • 设置项参考mcp.allowed / mcp.excluded 等全局开关的完整说明;
  • 核心实现源码:mcp-client.ts(连接、传输选择、状态机、通知刷新)、mcp-tool.ts(工具包装与 FQN 命名)、mcpCommand.ts/mcp 命令族)、mcp add 命令

掌握这条"配置 → 发现 → 命名 → 确认 → 执行"的主线后,接入 Slack、Postgres、Google Drive 等任意 MCP 服务器都只是替换 command / urlenv 的差异,其余流程完全一致。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
980
502
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384