1. 从一次 CLI 扩展联调失败说起
Gemini 3 的 Extensions 是把提示词、MCP 服务器、Agent Skills 和自定义命令打包成一个可分发单元的能力,适合需要在命令行里沉淀团队工作流的开发者。它解决的问题很具体:你写好的 MCP 工具、审计技能、代码检索命令,不用每次手动复制到~/.gemini,而是通过一个gemini-extension.json声明、一条gemini extensions link命令挂载,重启 CLI 就能被模型调用。适合谁?适合已经在用 Gemini CLI、想让 Agent 具备“专属工具”和“按需技能”的人,尤其是做内部工具链、代码审查、数据查询这类重复场景的团队。
我试过在本地把一个 TypeScript 写的 MCP 扩展 link 进 CLI,结果模型一直说“找不到工具”,排查半天发现是dist/example.js没构建、cwd又指错了目录。这类问题在扩展开发里非常典型:原理不难,难在配置骨架和验证动作要对齐。这篇就按“原理 → 前置接入 → 可复制配置 → 验证 → 排障 → 发布”的链路走一遍,重点交付能直接抄的config.toml、settings.json骨架,以及用 TaoToken 统一 Key 接入 CLI 的步骤。Extensions 与 MCP、Agent Skills 的协作机制,本质是 CLI 启动时扫描扩展目录,把 MCP server 注册进工具池,把 Skills 注册成按需触发的专家能力,再由模型在对话中决定调用哪个。
2. TaoToken 前置:统一 Key 与 CLI 接入准备
在写扩展之前,先把 CLI 的模型接入层理顺。TaoToken 在这里的角色是统一 Key 网关:你不需要在扩展里硬编码任何模型凭证,扩展只负责声明工具和技能,模型调用走 CLI 的全局配置。官网入口是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 基址是 https://taotoken.net/api (不加 UTM)。
操作顺序建议这样:先到控制台创建 API Key,地址 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite ;然后在 API Keys 页面复制 Key,地址 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 。接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,里面有 base_url 和鉴权头的完整说明。
注意:扩展的
settings字段只用于扩展自身的第三方服务 Key,不要把你的模型网关 Key 写进gemini-extension.json。模型 Key 属于 CLI 全局配置,扩展通过环境变量继承即可。
如果你打算长期跑编码类 Agent,可以了解 Coding Plan,地址 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite ,它更适合高频 CLI 调用场景。想先验证模型连通性,用模型对话页 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite 发一条测试消息即可。
3. 可复制配置:config.toml 与 settings.json 骨架
这一节是全文的核心交付。Gemini CLI 的配置分两层:全局层用config.toml管模型接入,扩展层用gemini-extension.json管工具与技能声明,而settings.json用于工作区级别的行为覆盖。下面给出可直接复制的骨架。
先看全局~/.gemini/config.toml,重点是模型网关指向 TaoToken:
# ~/.gemini/config.toml [model] provider = "openai-compatible" base_url = "https://taotoken.net/api" api_key_env = "TAOTOKEN_API_KEY" default_model = "gemini-3-pro" [cli] theme = "dark" checkpoint = true sandbox = false [extensions] enabled = true auto_link = true对应的环境变量在 shell 里导出,不要写死在文件里:
export TAOTOKEN_API_KEY="sk-你的Key"再看扩展的核心声明gemini-extension.json,这是扩展的“身份证”,决定它如何被加载:
{ "name": "my-first-extension", "version": "1.0.0", "contextFileName": "GEMINI.md", "mcpServers": { "nodeServer": { "command": "node", "args": ["${extensionPath}${/}dist${/}example.js"], "cwd": "${extensionPath}" } }, "settings": [ { "name": "API Key", "description": "Your API key for the service.", "envVar": "MY_API_KEY", "sensitive": true } ] }${extensionPath}保证扩展无论装在哪,路径都能解析;${/}是跨平台分隔符,Windows 和 macOS 都能用。settings里的sensitive: true会让 CLI 在安装时安全提示输入,并存到扩展目录下的.env。
工作区级别的settings.json放在项目根目录的.gemini/下,用于覆盖全局行为:
{ "extensions": { "disabled": ["noisy-extension"], "scope": "workspace" }, "model": { "temperature": 0.2 } }自定义命令用 TOML 声明,放在扩展的commands/fs/grep-code.toml:
prompt = """ 请总结以下模式的搜索结果 `{{args}}`。 搜索结果: !{grep -r {{args}} .} """Agent Skills 放在skills/security-audit/SKILL.md,按需触发,不常驻内存。MCP 工具代码在example.ts里注册:
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { z } from 'zod'; const server = new McpServer({ name: 'prompt-server', version: '1.0.0' }); server.registerTool('fetch_posts', { description: '从公共 API 获取帖子列表。', inputSchema: z.object({}).shape, }, async () => { const apiResponse = await fetch('https://jsonplaceholder.typicode.com/posts'); const posts = await apiResponse.json(); return { content: [{ type: 'text', text: JSON.stringify(posts.slice(0, 5)) }] }; });构建与本地链接三步走:
cd my-first-extension npm install npm run build gemini extensions link .4. 验证请求:CLI 侧成功结果确认
配置写完必须验证,否则你永远不知道是模型没连上还是扩展没挂载。验证分三层,逐层排除。
第一层,确认模型网关通。在 CLI 里直接发一条普通对话,或者用模型对话页测试。如果返回正常,说明config.toml的base_url和TAOTOKEN_API_KEY生效。
第二层,确认扩展被加载。运行:
gemini extensions list你应该能看到my-first-extension处于 enabled 状态。如果没出现,检查~/.gemini/extensions/下是否有软链接指向你的开发目录。
第三层,确认 MCP 工具可调用。重启 CLI 后对模型说“Fetch posts”,预期结果是模型调用fetch_posts工具并返回前 5 条帖子 JSON。成功时你会看到工具调用记录和结构化文本输出。自定义命令则输入/fs:grep-code "console.log",模型会自动执行 grep 并总结结果。
提示:如果工具调用返回空,先在终端手动跑
node dist/example.js,确认 MCP server 本身能启动。扩展问题里,一半以上是构建产物缺失或路径错误。
5. 本篇常见错排查
报错一:模型提示找不到工具。最常见原因是dist/example.js没生成。跑npm run build后确认dist目录存在。其次是cwd没设成${extensionPath},导致相对路径解析失败。
报错二:扩展命令与用户命令冲突。当扩展命令和用户已有命令同名,CLI 会自动加扩展名前缀,比如/gcp.deploy。如果你手动写了同名命令,检查是否被前缀规则覆盖。
报错三:settings 里的 Key 没注入。确认envVar名称和代码里读取的环境变量一致,且安装时确实输入了值。.env文件在扩展目录下,权限要收紧。
报错四:link 后改动不生效。link是软链接,但 TypeScript 需要重新npm run build。改完源码不构建,CLI 加载的还是旧dist。
报错五:发布后用户装不上。Git 仓库发布要确保仓库公开、gemini-extension.json在根目录。GitHub Releases 发布要遵循命名规范{平台}.{架构}.{扩展名}.{压缩格式},例如darwin.arm64.my-tool.tar.gz,否则 CLI 无法自动匹配平台。
日常管理命令备查:安装gemini extensions install <github-url-or-local-path>,更新gemini extensions update <name>(全部更新加--all),禁用gemini extensions disable <name> --scope workspace,卸载gemini extensions uninstall <name>。
6. 发布实践与后续接入
发布有两条路。日常迭代走 Git 仓库:推送到公开 GitHub 仓库,用户用 URL 安装,你还能用--ref=stable管理发布通道,dev 分支开发、stable 分支稳定。生产环境走 GitHub Releases:适合含编译步骤或平台二进制的扩展,用 GitHub Actions 自动构建多平台包,用户下载打包好的压缩文件,速度更快。
发布前建议在本地做一次完整联调:gemini extensions link .挂载开发目录,跑通 MCP 工具、自定义命令、Agent Skills 三条路径,再gemini extensions uninstall后从 Git URL 重装一次,确认发布形态没问题。
扩展开发完成后,模型调用仍然走你的统一 Key。排障和接入细节看 API Keys 页 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 和接入文档 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ;验证模型用模型对话 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite ;长期编码和 Agent 场景用 Coding Plan https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite 。Claude Code 相关接入参考 https://taotoken.net/claude-code?utm_source=taotoken_aicg_blog_end&utm_content=claude-code&utm_campaign=rewrite 。把扩展的settings和 CLI 的全局 Key 分层管好,你的 CLI 工具链就能既安全又可分发。