mirror of
https://github.com/chainbase-labs/Agentkey.git
synced 2026-09-20 14:20:23 +08:00
fix(plugins): package Gemini releases and improve OAuth (#94)
## Summary - preserve the existing `agentkey.skill` GitHub Release asset and add platform-named Gemini extension archives for macOS, Linux, and Windows - opt the Gemini extension into native first-connect OAuth with `oauth.enabled`, while keeping `/mcp auth agentkey` as the manual retry path - add explicit Gemini, Antigravity 2.0, and Antigravity CLI authentication and connection-verification guidance - explain Gemini's user-Skill precedence warning and avoid duplicate MCP registrations when an extension or plugin already owns the server entry - add regression coverage and trigger the scripts test workflow when authentication guidance or release packaging changes ## Root causes Gemini CLI treats a lone generic GitHub Release asset as the extension archive. AgentKey releases currently publish only `agentkey.skill`, but Gemini CLI extracts only `.tar.gz` and `.zip` extension archives. After that extraction failure, Gemini retries Git clone in the same non-empty temporary directory and fails again. Separately, the Gemini manifest omitted `oauth.enabled`. Gemini discovered that AgentKey required OAuth, but only reported `/mcp auth agentkey` instead of starting the browser flow automatically. A pre-existing user Skill at `~/.agents/skills/agentkey` can also override the extension-bundled Skill, hiding new setup guidance even though the extension MCP entry is active. ## Authentication design - Gemini uses `httpUrl` plus `oauth.enabled: true`; OAuth endpoints and client registration remain dynamically discovered. - Antigravity keeps the documented credential-free `serverUrl` configuration and uses DCR through its native Authenticate controls. - No static access token, Authorization header, OAuth client secret, or hard-coded authorization endpoint is added to either package. ## Validation - Bats suite: 27/27 passing - `gemini extensions validate .` - built and inspected `agentkey.skill`, `darwin.agentkey.tar.gz`, `linux.agentkey.tar.gz`, and `win32.agentkey.zip` - verified both Gemini platform archive formats contain `oauth.enabled: true`, `gemini-extension.json`, and `skills/agentkey/SKILL.md` - validated workflow YAML, shell syntax, archive roots, manifest invariants, and `git diff --check` - verified the live AgentKey endpoint advertises protected-resource metadata, PKCE, and a dynamic client registration endpoint ## Release coordination Merge this fix before release PR #92 so the first Gemini-enabled release publishes compatible archives and the corrected first-connect OAuth behavior. --------- Co-authored-by: Allen <0xfatdog@gmail.com>
This commit is contained in:
+9
-3
@@ -21,7 +21,7 @@ It also works as a **Cursor plugin** (`.cursor-plugin/plugin.json`). The Cursor-
|
||||
|
||||
It also works as a **Kimi Code plugin** (`.kimi-plugin/plugin.json`). Kimi requires `mcpServers` to be an inline object in the manifest. The remote AgentKey endpoint uses Kimi's native MCP OAuth flow; after install Kimi shows the standard `/reload` hint, then the user signs in with `/mcp-config login plugin-agentkey:agentkey` when Kimi reports that OAuth is required.
|
||||
|
||||
It also works as a **Gemini CLI extension** (root `gemini-extension.json` + `skills/`). Gemini requires the manifest at the extension root, discovers bundled agent skills automatically, and connects to AgentKey with `httpUrl` plus native MCP OAuth discovery. `/mcp auth agentkey` substitutes for step 2.
|
||||
It also works as a **Gemini CLI extension** (root `gemini-extension.json` + `skills/`). Gemini requires the manifest at the extension root, discovers bundled agent skills automatically, and connects to AgentKey with `httpUrl` plus native MCP OAuth discovery. `oauth.enabled` requests the browser flow automatically; `/mcp auth agentkey` is the manual fallback. Either substitutes for step 2.
|
||||
|
||||
It also works as an **Antigravity 2.0 and Antigravity CLI plugin** (root `plugin.json` + `mcp_config.json` + `skills/`). Both runtimes use the same package, require `serverUrl` for remote MCP, and authenticate through automatic OAuth discovery.
|
||||
|
||||
@@ -47,6 +47,7 @@ agentkey/
|
||||
│ ├── scripts/ # check-update helper
|
||||
│ └── version.txt # Managed by release-please only — must live inside the skill so it survives `npx skills add`
|
||||
└── scripts/
|
||||
├── build-release-assets.sh # Builds Skill + Gemini GitHub Release assets
|
||||
└── uninstall.sh # End-user cleanup helper
|
||||
```
|
||||
|
||||
@@ -110,10 +111,15 @@ Releases are driven by [release-please](https://github.com/googleapis/release-pl
|
||||
**Changes to `gemini-extension.json`:**
|
||||
- The manifest MUST remain at the repository root because Gemini installs the repository as the extension root and expects the extension name to match its install directory.
|
||||
- Keep `mcpServers.agentkey` inline and use `httpUrl` for the Streamable HTTP endpoint. Do not use the SSE-only `url` field for `/v1/mcp`.
|
||||
- Do not add static credentials, `settings`, custom headers, or `trust`. Gemini discovers the AgentKey OAuth metadata after the server's 401, and users authenticate with `/mcp auth agentkey`.
|
||||
- Keep `oauth` limited to `{"enabled":true}` so Gemini starts its native browser flow after the server's 401 while still discovering all endpoints dynamically. Do not add static credentials, OAuth endpoints/client credentials, `settings`, custom headers, or `trust`. `/mcp auth agentkey` remains the manual fallback.
|
||||
- Do not duplicate `skills/agentkey/` or add an always-loaded `GEMINI.md`; Gemini discovers the existing skill automatically.
|
||||
- Keep the endpoint URL in sync with `.mcp.json`, `.codex-plugin/mcp.json`, `.cursor-plugin/plugin.json`, and `.kimi-plugin/plugin.json`.
|
||||
|
||||
**Changes to GitHub Release assets:**
|
||||
- Keep `agentkey.skill` for Skill consumers, but never publish it as the only generic Release asset. Gemini CLI treats a lone generic asset as an extension archive and only extracts `.tar.gz` or `.zip` files.
|
||||
- Run `scripts/build-release-assets.sh` to produce `agentkey.skill` plus `darwin.agentkey.tar.gz`, `linux.agentkey.tar.gz`, and `win32.agentkey.zip`.
|
||||
- Every platform-named Gemini archive MUST contain `gemini-extension.json` and `skills/agentkey/SKILL.md` at its archive root. Keep the platform prefixes so Gemini selects these archives before `agentkey.skill`.
|
||||
|
||||
**Changes to root `plugin.json` / `mcp_config.json`:**
|
||||
- Keep both files at the repository root so Antigravity 2.0 and Antigravity CLI share one plugin package and reuse `skills/agentkey/` without duplication.
|
||||
- Keep `plugin.json` limited to the documented `$schema`, `name`, and `description` fields. The Antigravity schema has no `version` field, so release-please must not add one.
|
||||
@@ -133,6 +139,6 @@ Releases are driven by [release-please](https://github.com/googleapis/release-pl
|
||||
- `.mcp.json` registers the remote-HTTP MCP endpoint (`https://api.agentkey.app/v1/mcp`) in Claude Code plugin mode; the API key flows from plugin userConfig into the `Authorization: Bearer ${user_config.AGENTKEY_API_KEY}` header (no stdio binary is launched)
|
||||
- `.cursor-plugin/plugin.json` registers the same endpoint inline in Cursor plugin mode, authenticated through Cursor's native MCP OAuth flow
|
||||
- `.kimi-plugin/plugin.json` registers the same endpoint inline in Kimi Code plugin mode. After reloading, the user starts Kimi's native MCP OAuth flow with `/mcp-config login plugin-agentkey:agentkey`.
|
||||
- `gemini-extension.json` registers the same endpoint through `httpUrl` in Gemini CLI extension mode. Gemini discovers the existing `skills/agentkey/` tree and authenticates through `/mcp auth agentkey`.
|
||||
- `gemini-extension.json` registers the same endpoint through `httpUrl` in Gemini CLI extension mode. Gemini discovers the existing `skills/agentkey/` tree; `oauth.enabled` starts native OAuth automatically and `/mcp auth agentkey` retries it manually.
|
||||
- Root `plugin.json` and `mcp_config.json` package the existing skill and the same endpoint for both Antigravity 2.0 and Antigravity CLI; remote MCP uses `serverUrl` and automatic OAuth discovery.
|
||||
- `README.md` / `docs/README_zh.md` are the public-facing docs; keep them in sync with any structural changes
|
||||
|
||||
@@ -22,29 +22,28 @@ jobs:
|
||||
config-file: release-please-config.json
|
||||
manifest-file: .release-please-manifest.json
|
||||
|
||||
publish-skill-asset:
|
||||
publish-release-assets:
|
||||
needs: release-please
|
||||
if: ${{ needs.release-please.outputs.release_created == 'true' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ needs.release-please.outputs.tag_name }}
|
||||
|
||||
- name: Build agentkey.skill zip
|
||||
run: |
|
||||
cd skills/agentkey
|
||||
zip -r "$GITHUB_WORKSPACE/agentkey.skill" . \
|
||||
-x "*.DS_Store" \
|
||||
-x "__pycache__/*" \
|
||||
-x "*.pyc"
|
||||
echo "--- contents ---"
|
||||
unzip -l "$GITHUB_WORKSPACE/agentkey.skill"
|
||||
- name: Build Skill and Gemini extension assets
|
||||
run: scripts/build-release-assets.sh dist/release-assets
|
||||
|
||||
- name: Upload asset to release
|
||||
- name: Upload assets to release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAG: ${{ needs.release-please.outputs.tag_name }}
|
||||
run: |
|
||||
gh release upload "$TAG" agentkey.skill \
|
||||
gh release upload "$TAG" \
|
||||
dist/release-assets/agentkey.skill \
|
||||
dist/release-assets/darwin.agentkey.tar.gz \
|
||||
dist/release-assets/linux.agentkey.tar.gz \
|
||||
dist/release-assets/win32.agentkey.zip \
|
||||
--repo "$GITHUB_REPOSITORY" \
|
||||
--clobber
|
||||
|
||||
|
||||
@@ -3,18 +3,31 @@ on:
|
||||
push:
|
||||
paths:
|
||||
- 'skills/agentkey/scripts/**'
|
||||
- 'scripts/build-release-assets.sh'
|
||||
- 'skills/agentkey/SKILL.md'
|
||||
- 'skills/agentkey/references/setup.md'
|
||||
- 'gemini-extension.json'
|
||||
- 'plugin.json'
|
||||
- 'mcp_config.json'
|
||||
- 'README.md'
|
||||
- 'docs/README_zh.md'
|
||||
- 'tests/**'
|
||||
- '.github/workflows/release-please.yml'
|
||||
- '.github/workflows/scripts-test.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'skills/agentkey/scripts/**'
|
||||
- 'scripts/build-release-assets.sh'
|
||||
- 'skills/agentkey/SKILL.md'
|
||||
- 'skills/agentkey/references/setup.md'
|
||||
- 'gemini-extension.json'
|
||||
- 'plugin.json'
|
||||
- 'mcp_config.json'
|
||||
- 'README.md'
|
||||
- 'docs/README_zh.md'
|
||||
- 'tests/**'
|
||||
- '.github/workflows/release-please.yml'
|
||||
- '.github/workflows/scripts-test.yml'
|
||||
|
||||
jobs:
|
||||
bats:
|
||||
|
||||
@@ -19,7 +19,7 @@ The same repo also works as:
|
||||
- a **Codex plugin** (`.codex-plugin/plugin.json` + `.codex-plugin/mcp.json`, distributed through `.agents/plugins/marketplace.json`; the repo is its own marketplace: `codex plugin marketplace add chainbase-labs/agentkey`). Codex plugins have no `userConfig`/header-interpolation mechanism, so auth uses MCP OAuth via the server's RFC 9728 metadata discovery (`type` + `url` only in mcp.json), substituting for step 2.
|
||||
- a **Cursor plugin** (`.cursor-plugin/plugin.json`). The Cursor-native manifest bundles `skills/` and an inline remote-HTTP MCP entry. Cursor authenticates through the server's MCP OAuth discovery, substituting for step 2.
|
||||
- a **Kimi Code plugin** (`.kimi-plugin/plugin.json`). Kimi requires `mcpServers` to be an inline object in the manifest. The remote AgentKey endpoint uses Kimi's native MCP OAuth flow; after install Kimi shows the standard `/reload` hint, then the user signs in with `/mcp-config login plugin-agentkey:agentkey` when Kimi reports that OAuth is required.
|
||||
- a **Gemini CLI extension** (root `gemini-extension.json` + `skills/`). Gemini requires the manifest at the extension root, discovers bundled agent skills automatically, and connects to AgentKey with `httpUrl` plus native MCP OAuth discovery. `/mcp auth agentkey` substitutes for step 2.
|
||||
- a **Gemini CLI extension** (root `gemini-extension.json` + `skills/`). Gemini requires the manifest at the extension root, discovers bundled agent skills automatically, and connects to AgentKey with `httpUrl` plus native MCP OAuth discovery. `oauth.enabled` requests the browser flow automatically; `/mcp auth agentkey` is the manual fallback. Either substitutes for step 2.
|
||||
- an **Antigravity 2.0 and Antigravity CLI plugin** (root `plugin.json` + `mcp_config.json` + `skills/`). Both runtimes use the same package, require `serverUrl` for remote MCP, and authenticate through automatic OAuth discovery.
|
||||
|
||||
## Directory Structure
|
||||
@@ -44,6 +44,7 @@ agentkey/
|
||||
│ ├── scripts/ # check-update helper
|
||||
│ └── version.txt # Managed by release-please only — must live inside the skill so it survives `npx skills add`
|
||||
└── scripts/
|
||||
├── build-release-assets.sh # Builds Skill + Gemini GitHub Release assets
|
||||
└── uninstall.sh # End-user cleanup helper
|
||||
```
|
||||
|
||||
@@ -107,10 +108,15 @@ Releases are driven by [release-please](https://github.com/googleapis/release-pl
|
||||
**Changes to `gemini-extension.json` (Gemini CLI extension path):**
|
||||
- The manifest MUST remain at the repository root because Gemini installs the repository as the extension root and expects the extension name to match its install directory.
|
||||
- Keep `mcpServers.agentkey` inline and use `httpUrl` for the Streamable HTTP endpoint. Do not use the SSE-only `url` field for `/v1/mcp`.
|
||||
- Do not add static credentials, `settings`, custom headers, or `trust`. Gemini discovers the AgentKey OAuth metadata after the server's 401, and users authenticate with `/mcp auth agentkey`.
|
||||
- Keep `oauth` limited to `{"enabled":true}` so Gemini starts its native browser flow after the server's 401 while still discovering all endpoints dynamically. Do not add static credentials, OAuth endpoints/client credentials, `settings`, custom headers, or `trust`. `/mcp auth agentkey` remains the manual fallback.
|
||||
- Do not duplicate `skills/agentkey/` or add an always-loaded `GEMINI.md`; Gemini discovers the existing skill automatically.
|
||||
- Keep the endpoint URL in sync with `.mcp.json`, `.codex-plugin/mcp.json`, `.cursor-plugin/plugin.json`, and `.kimi-plugin/plugin.json`.
|
||||
|
||||
**Changes to GitHub Release assets:**
|
||||
- Keep `agentkey.skill` for Skill consumers, but never publish it as the only generic Release asset. Gemini CLI treats a lone generic asset as an extension archive and only extracts `.tar.gz` or `.zip` files.
|
||||
- Run `scripts/build-release-assets.sh` to produce `agentkey.skill` plus `darwin.agentkey.tar.gz`, `linux.agentkey.tar.gz`, and `win32.agentkey.zip`.
|
||||
- Every platform-named Gemini archive MUST contain `gemini-extension.json` and `skills/agentkey/SKILL.md` at its archive root. Keep the platform prefixes so Gemini selects these archives before `agentkey.skill`.
|
||||
|
||||
**Changes to root `plugin.json` / `mcp_config.json` (Antigravity plugin path):**
|
||||
- Keep both files at the repository root so Antigravity 2.0 and Antigravity CLI share one plugin package and reuse `skills/agentkey/` without duplication.
|
||||
- Keep `plugin.json` limited to the documented `$schema`, `name`, and `description` fields. The Antigravity schema has no `version` field, so release-please must not add one.
|
||||
@@ -131,6 +137,6 @@ Releases are driven by [release-please](https://github.com/googleapis/release-pl
|
||||
- `.codex-plugin/mcp.json` registers the same endpoint in Codex plugin mode, authenticated via MCP OAuth (RFC 9728 discovery; no `oauth_resource` — see checklist above)
|
||||
- `.cursor-plugin/plugin.json` registers the same endpoint inline in Cursor plugin mode, authenticated through Cursor's native MCP OAuth flow
|
||||
- `.kimi-plugin/plugin.json` registers the same endpoint inline in Kimi Code plugin mode. After reloading, the user starts Kimi's native MCP OAuth flow with `/mcp-config login plugin-agentkey:agentkey`.
|
||||
- `gemini-extension.json` registers the same endpoint through `httpUrl` in Gemini CLI extension mode. Gemini discovers the existing `skills/agentkey/` tree and authenticates through `/mcp auth agentkey`.
|
||||
- `gemini-extension.json` registers the same endpoint through `httpUrl` in Gemini CLI extension mode. Gemini discovers the existing `skills/agentkey/` tree; `oauth.enabled` starts native OAuth automatically and `/mcp auth agentkey` retries it manually.
|
||||
- Root `plugin.json` and `mcp_config.json` package the existing skill and the same endpoint for both Antigravity 2.0 and Antigravity CLI; remote MCP uses `serverUrl` and automatic OAuth discovery.
|
||||
- `README.md` / `docs/README_zh.md` are the public-facing docs; keep them in sync with any structural changes
|
||||
|
||||
@@ -394,9 +394,11 @@ gemini extensions install https://github.com/chainbase-labs/agentkey
|
||||
gemini extensions link /absolute/path/to/agentkey
|
||||
```
|
||||
|
||||
Restart Gemini CLI after installing or linking. If the MCP server requires authentication, run `/mcp auth agentkey` and approve the browser authorization; Gemini then stores and refreshes the OAuth tokens. Use `/mcp reload` after changing the server configuration.
|
||||
Restart Gemini CLI after installing or linking. On the first connection, the extension's `oauth.enabled` setting asks Gemini to start its native browser authorization automatically. Complete that flow, then run `/mcp reload` and `/mcp list` to confirm that `agentkey` is connected. If Gemini only reports that authentication is required, or the browser flow was closed, run `/mcp auth agentkey` to start it manually. Gemini stores and refreshes the OAuth tokens, so this is normally a one-time sign-in. Do not add a second user-level MCP entry or run `@agentkey/cli --auth-login` in extension mode.
|
||||
|
||||
**Antigravity 2.0 / Antigravity CLI plugin mode** — both runtimes use the root `plugin.json`, `mcp_config.json`, and existing `skills/` directory. The MCP entry uses Antigravity's `serverUrl` schema and automatic OAuth discovery, so there is **no API key to paste and no second `@agentkey/cli` step**.
|
||||
If Gemini reports that `~/.agents/skills/agentkey` overrides the copy bundled by the extension, that is a separate Skill-precedence warning rather than an OAuth failure. A previously installed user Skill has higher priority and can safely remain when it is the same version—especially if other agents use that shared directory. Remove it with `gemini skills uninstall agentkey --scope user` only when it is no longer needed elsewhere, then run `/skills reload`.
|
||||
|
||||
**Antigravity 2.0 / Antigravity CLI plugin mode** — both runtimes use the root `plugin.json`, `mcp_config.json`, and existing `skills/` directory. The MCP entry uses Antigravity's `serverUrl` schema and automatic OAuth discovery through dynamic client registration, so there is **no API key to paste, no OAuth client secret to configure, and no second `@agentkey/cli` step**.
|
||||
|
||||
For Antigravity 2.0, place the repository at workspace scope or global scope, then restart Antigravity:
|
||||
|
||||
@@ -415,7 +417,12 @@ agy plugin install /absolute/path/to/agentkey
|
||||
agy plugin list
|
||||
```
|
||||
|
||||
Antigravity 2.0 exposes OAuth through **Settings → Customizations → Authenticate**. In Antigravity CLI, open `/mcp` to inspect or reload the server and follow the authentication prompt when it first connects.
|
||||
After Antigravity discovers the plugin, authenticate its bundled MCP entry rather than adding a duplicate:
|
||||
|
||||
- **Antigravity 2.0:** open **Settings → Customizations → Installed MCP Servers**, click **Authenticate** next to AgentKey, complete the browser flow, copy the authorization code back into the settings panel, and submit it. The server reconnects automatically; click **Refresh** if the status does not update.
|
||||
- **Antigravity CLI:** open `/mcp`, select `agentkey`, choose **Authenticate**, and follow the browser/code prompts. Reload the server in the same panel and confirm the AgentKey tools are listed; inspect its connection logs there if it remains disconnected.
|
||||
|
||||
Keep `mcp_config.json` free of static headers, access tokens, and OAuth client credentials. AgentKey publishes protected-resource and authorization-server metadata, including a dynamic registration endpoint, for both Antigravity runtimes to discover.
|
||||
|
||||
**Repo layout:**
|
||||
|
||||
@@ -439,13 +446,14 @@ agentkey/
|
||||
│ ├── scripts/ # check-update helper
|
||||
│ └── version.txt # Managed by release-please
|
||||
└── scripts/
|
||||
├── build-release-assets.sh # Build Skill + Gemini GitHub Release assets
|
||||
├── install.sh # One-command installer (mac/linux)
|
||||
├── install.ps1 # Windows PowerShell installer
|
||||
├── uninstall.sh # One-command uninstaller (mac/linux)
|
||||
└── uninstall.ps1 # Windows PowerShell uninstaller
|
||||
```
|
||||
|
||||
**Release a new version (maintainers):** releases are cut automatically by [release-please](https://github.com/googleapis/release-please). Merging a PR with a `feat:` or `fix:` title opens a Release PR that bumps `skills/agentkey/version.txt`, all four versioned plugin manifests, `gemini-extension.json`, and `CHANGELOG.md`. The Antigravity schema has no `version` field, so its root `plugin.json` is not part of version syncing. Merging the Release PR creates the tag + GitHub Release + uploads the `agentkey.skill` asset.
|
||||
**Release a new version (maintainers):** releases are cut automatically by [release-please](https://github.com/googleapis/release-please). Merging a PR with a `feat:` or `fix:` title opens a Release PR that bumps `skills/agentkey/version.txt`, all four versioned plugin manifests, `gemini-extension.json`, and `CHANGELOG.md`. The Antigravity schema has no `version` field, so its root `plugin.json` is not part of version syncing. Merging the Release PR creates the tag + GitHub Release, preserves the `agentkey.skill` asset, and uploads platform-named Gemini extension archives whose roots contain `gemini-extension.json`.
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
+12
-4
@@ -394,9 +394,11 @@ gemini extensions install https://github.com/chainbase-labs/agentkey
|
||||
gemini extensions link /absolute/path/to/agentkey
|
||||
```
|
||||
|
||||
安装或链接后重启 Gemini CLI。如果 MCP server 提示需要认证,执行 `/mcp auth agentkey` 并在浏览器完成授权;之后 Gemini 会保存并自动刷新 OAuth token。修改 server 配置后可执行 `/mcp reload`。
|
||||
安装或链接后重启 Gemini CLI。首次连接时,extension 的 `oauth.enabled` 会要求 Gemini 自动启动原生浏览器授权;完成授权后执行 `/mcp reload` 和 `/mcp list`,确认 `agentkey` 已连接。如果 Gemini 只提示需要认证,或者浏览器流程被关闭,则执行 `/mcp auth agentkey` 手动重新发起。Gemini 会保存并自动刷新 OAuth token,因此通常只需要登录一次。Extension 模式下不要再添加一条用户级 MCP 配置,也不要运行 `@agentkey/cli --auth-login`。
|
||||
|
||||
**Antigravity 2.0 / Antigravity CLI 插件模式** —— 两个运行时共用根目录的 `plugin.json`、`mcp_config.json` 和现有 `skills/`。MCP 配置使用 Antigravity 规定的 `serverUrl` 并依赖自动 OAuth discovery,**不用粘贴 API Key,也不需要再单独运行 `@agentkey/cli`**。
|
||||
如果 Gemini 提示 `~/.agents/skills/agentkey` 覆盖了 extension 捆绑的 Skill,这是独立的 Skill 优先级告警,不是 OAuth 失败。之前安装的用户级 Skill 优先级更高;当两份版本一致时可以安全保留,尤其是其他 Agent 也依赖这个共享目录时。只有确认其他 Agent 不再需要它之后,才执行 `gemini skills uninstall agentkey --scope user`,再运行 `/skills reload`。
|
||||
|
||||
**Antigravity 2.0 / Antigravity CLI 插件模式** —— 两个运行时共用根目录的 `plugin.json`、`mcp_config.json` 和现有 `skills/`。MCP 配置使用 Antigravity 规定的 `serverUrl`,并通过动态客户端注册自动发现 OAuth,**不用粘贴 API Key、不用配置 OAuth client secret,也不需要再单独运行 `@agentkey/cli`**。
|
||||
|
||||
Antigravity 2.0 可按 workspace 或全局范围放置插件,完成后重启 Antigravity:
|
||||
|
||||
@@ -415,7 +417,12 @@ agy plugin install /absolute/path/to/agentkey
|
||||
agy plugin list
|
||||
```
|
||||
|
||||
Antigravity 2.0 在 **Settings → Customizations → Authenticate** 中完成 OAuth。Antigravity CLI 首次连接时按认证提示操作;需要检查状态或重新加载 server 时打开 `/mcp`。
|
||||
Antigravity 发现插件后,应认证插件捆绑的 MCP 配置,不要重复添加另一条 server:
|
||||
|
||||
- **Antigravity 2.0:**打开 **Settings → Customizations → Installed MCP Servers**,在 AgentKey 旁点击 **Authenticate**;在浏览器完成授权后,把 authorization code 复制回设置面板并提交。Server 会自动重连;状态没有更新时点击 **Refresh**。
|
||||
- **Antigravity CLI:**打开 `/mcp`,选择 `agentkey` 并点击 **Authenticate**,按界面给出的浏览器/验证码流程完成授权;在同一面板 reload server,确认 AgentKey 工具已经出现。如果仍是 disconnected,可直接在这里检查连接日志。
|
||||
|
||||
不要在 `mcp_config.json` 中写入静态 header、access token 或 OAuth client credential。AgentKey 已发布 protected-resource 与 authorization-server metadata,并提供 dynamic registration endpoint,两个 Antigravity 运行时都应通过这些元数据完成发现。
|
||||
|
||||
**仓库结构:**
|
||||
|
||||
@@ -439,13 +446,14 @@ agentkey/
|
||||
│ ├── scripts/ # check-update 辅助脚本
|
||||
│ └── version.txt # 由 release-please 自动维护
|
||||
└── scripts/
|
||||
├── build-release-assets.sh # 构建 Skill + Gemini GitHub Release 产物
|
||||
├── install.sh # 一键安装脚本(mac/linux)
|
||||
├── install.ps1 # Windows PowerShell 安装脚本
|
||||
├── uninstall.sh # 一键卸载脚本(mac/linux)
|
||||
└── uninstall.ps1 # Windows PowerShell 卸载脚本
|
||||
```
|
||||
|
||||
**发布新版本(Maintainer):** 发版由 [release-please](https://github.com/googleapis/release-please) 自动触发。合并一个 `feat:` 或 `fix:` 的 PR 后,release-please 会开一个 Release PR,自动 bump `skills/agentkey/version.txt`、四个带版本号的插件清单、`gemini-extension.json` 和 `CHANGELOG.md`。Antigravity schema 没有 `version` 字段,因此根目录 `plugin.json` 不参与版本同步。合并这个 Release PR 即会创建 tag + GitHub Release + 上传 `agentkey.skill` 产物。
|
||||
**发布新版本(Maintainer):** 发版由 [release-please](https://github.com/googleapis/release-please) 自动触发。合并一个 `feat:` 或 `fix:` 的 PR 后,release-please 会开一个 Release PR,自动 bump `skills/agentkey/version.txt`、四个带版本号的插件清单、`gemini-extension.json` 和 `CHANGELOG.md`。Antigravity schema 没有 `version` 字段,因此根目录 `plugin.json` 不参与版本同步。合并这个 Release PR 即会创建 tag + GitHub Release,保留 `agentkey.skill` 产物,并上传根目录包含 `gemini-extension.json` 的平台命名 Gemini 扩展压缩包。
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
"description": "AgentKey gives Gemini CLI one-stop access to live web, social, finance, crypto, e-commerce, business, weather, maps, and travel data.",
|
||||
"mcpServers": {
|
||||
"agentkey": {
|
||||
"httpUrl": "https://api.agentkey.app/v1/mcp"
|
||||
"httpUrl": "https://api.agentkey.app/v1/mcp",
|
||||
"oauth": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Executable
+64
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
OUTPUT_ARG="${1:-dist/release-assets}"
|
||||
|
||||
case "$OUTPUT_ARG" in
|
||||
/*) OUTPUT_DIR="$OUTPUT_ARG" ;;
|
||||
*) OUTPUT_DIR="$REPO_ROOT/$OUTPUT_ARG" ;;
|
||||
esac
|
||||
|
||||
for command_name in git tar unzip zip; do
|
||||
if ! command -v "$command_name" >/dev/null 2>&1; then
|
||||
echo "Required command not found: $command_name" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
|
||||
ASSET_NAMES=(
|
||||
agentkey.skill
|
||||
darwin.agentkey.tar.gz
|
||||
linux.agentkey.tar.gz
|
||||
win32.agentkey.zip
|
||||
)
|
||||
|
||||
for asset_name in "${ASSET_NAMES[@]}"; do
|
||||
rm -f "$OUTPUT_DIR/$asset_name"
|
||||
done
|
||||
|
||||
(
|
||||
cd "$REPO_ROOT/skills/agentkey"
|
||||
zip -qr "$OUTPUT_DIR/agentkey.skill" . \
|
||||
-x "*.DS_Store" \
|
||||
-x "__pycache__/*" \
|
||||
-x "*.pyc"
|
||||
)
|
||||
|
||||
git -C "$REPO_ROOT" archive \
|
||||
--format=tar.gz \
|
||||
--output="$OUTPUT_DIR/darwin.agentkey.tar.gz" \
|
||||
HEAD
|
||||
cp "$OUTPUT_DIR/darwin.agentkey.tar.gz" "$OUTPUT_DIR/linux.agentkey.tar.gz"
|
||||
git -C "$REPO_ROOT" archive \
|
||||
--format=zip \
|
||||
--output="$OUTPUT_DIR/win32.agentkey.zip" \
|
||||
HEAD
|
||||
|
||||
for archive_name in darwin.agentkey.tar.gz linux.agentkey.tar.gz; do
|
||||
tar -tzf "$OUTPUT_DIR/$archive_name" | grep -Fx 'gemini-extension.json' >/dev/null
|
||||
tar -tzf "$OUTPUT_DIR/$archive_name" | grep -Fx 'skills/agentkey/SKILL.md' >/dev/null
|
||||
done
|
||||
|
||||
unzip -Z1 "$OUTPUT_DIR/win32.agentkey.zip" | grep -Fx 'gemini-extension.json' >/dev/null
|
||||
unzip -Z1 "$OUTPUT_DIR/win32.agentkey.zip" | grep -Fx 'skills/agentkey/SKILL.md' >/dev/null
|
||||
unzip -Z1 "$OUTPUT_DIR/agentkey.skill" | grep -Fx 'SKILL.md' >/dev/null
|
||||
|
||||
echo "Built release assets:"
|
||||
for asset_name in "${ASSET_NAMES[@]}"; do
|
||||
echo " $OUTPUT_DIR/$asset_name"
|
||||
done
|
||||
@@ -89,6 +89,14 @@ Never expose raw error details to the user.
|
||||
|
||||
The skill is useless without the AgentKey MCP server registered with the user's agent. Two ways to connect — **try OAuth first**; fall back to an API key only if OAuth isn't available.
|
||||
|
||||
Before adding anything, check whether an `agentkey` MCP server is already present but disconnected or waiting for authentication. Plugin and extension installs bundle that server entry. **Authenticate the bundled entry; do not register a duplicate server and do not run the standalone AgentKey CLI for that client.**
|
||||
|
||||
- **Gemini CLI extension:** the bundled MCP entry requests native OAuth automatically. Complete the browser flow when it opens. If Gemini only reports that authentication is required, run `/mcp auth agentkey` manually; then `/mcp reload` and confirm the server is connected with `/mcp list`.
|
||||
- **Antigravity 2.0 plugin:** open **Settings → Customizations → Installed MCP Servers**, click **Authenticate** next to AgentKey, complete the browser flow, paste the authorization code, and submit it.
|
||||
- **Antigravity CLI plugin:** open `/mcp`, select the `agentkey` server, choose **Authenticate**, follow the displayed browser/code prompts, then reload it and confirm it is connected.
|
||||
|
||||
If the client or its exact controls are uncertain, load `references/setup.md` and follow the matching client-specific flow.
|
||||
|
||||
### 1 — OAuth (preferred)
|
||||
|
||||
Register the hosted MCP server into **whatever client you're running in**, using that client's own mechanism (an `mcp add` CLI command, an MCP settings panel, or editing its config file). Connection params:
|
||||
|
||||
@@ -6,16 +6,58 @@ OAuth, or the OAuth flow fails.
|
||||
|
||||
## OAuth registration (preferred)
|
||||
|
||||
Add the server with **no API key** and let the client run its own browser OAuth —
|
||||
nothing to copy or store. The exact step depends on the client; these are
|
||||
examples, not the only supported clients:
|
||||
First check whether the client already lists an `agentkey` MCP server. Plugin
|
||||
and extension installs bundle that entry, so authenticate it in place. Do not
|
||||
add a second server and do not run `@agentkey/cli --auth-login` for that client.
|
||||
|
||||
### Gemini CLI extension
|
||||
|
||||
1. Confirm `agentkey` is active with `/extensions list`.
|
||||
2. On the first connection, the extension's `oauth.enabled` setting asks
|
||||
Gemini to start its native browser authorization automatically. Complete
|
||||
that flow when it opens.
|
||||
3. If Gemini only reports that authentication is required, or the browser flow
|
||||
was closed, run `/mcp auth agentkey` to start it manually.
|
||||
4. Run `/mcp reload`, then `/mcp list` and confirm `agentkey` is connected.
|
||||
5. Retry the original request only after `find_tools`, `describe_tool`, and
|
||||
`execute_tool` are visible.
|
||||
|
||||
A warning that `~/.agents/skills/agentkey` overrides the extension's bundled
|
||||
skill is separate from MCP authentication. Gemini gives user skills higher
|
||||
precedence than extension skills. If both copies are the same version, the
|
||||
warning is harmless. Remove the user copy only when no other agent relies on
|
||||
that shared skill directory.
|
||||
|
||||
### Antigravity plugin
|
||||
|
||||
AgentKey supports dynamic client registration, so keep `mcp_config.json`
|
||||
credential-free and authenticate the bundled `serverUrl` entry:
|
||||
|
||||
- **Antigravity 2.0:** open **Settings → Customizations → Installed MCP
|
||||
Servers**, click **Authenticate** next to AgentKey, complete the browser
|
||||
flow, copy the authorization code, paste it into the settings panel, and
|
||||
submit it. The server reconnects automatically; use **Refresh** if its status
|
||||
does not update.
|
||||
- **Antigravity CLI:** open `/mcp`, select the `agentkey` server, choose
|
||||
**Authenticate**, and follow the browser/code prompts shown by the manager.
|
||||
Reload the server in the same panel, inspect its logs if it remains
|
||||
disconnected, and retry only after the AgentKey tools appear.
|
||||
|
||||
Do not put OAuth client secrets, access tokens, or an `Authorization` header in
|
||||
the plugin package.
|
||||
|
||||
### Other clients
|
||||
|
||||
If no AgentKey server entry exists, add the server with **no API key** and let
|
||||
the client run its own browser OAuth. The exact step depends on the client;
|
||||
these are examples, not the only supported clients:
|
||||
|
||||
- **Claude Code:** `claude mcp add --transport http agentkey https://api.agentkey.app/v1/mcp`,
|
||||
then `/mcp` → agentkey → **Authenticate**.
|
||||
- **Cursor / Claude Desktop:** add a remote MCP server in settings with URL
|
||||
`https://api.agentkey.app/v1/mcp` and no auth header; the app prompts to sign
|
||||
in on first use.
|
||||
- **Any other client:** add the same URL as an HTTP MCP server with no
|
||||
- **Another client:** add the same URL as an HTTP MCP server with no
|
||||
`Authorization` header. If the client supports MCP OAuth it prompts to
|
||||
authorize on first connect; if it doesn't, use the API-key fallback below.
|
||||
|
||||
@@ -25,7 +67,9 @@ reconnects/restarts.
|
||||
|
||||
## API-key fallback
|
||||
|
||||
Use when the client can't do MCP OAuth, or OAuth failed.
|
||||
Use only when the client can't do MCP OAuth, or its native OAuth flow failed.
|
||||
An extension/plugin server that merely starts as disconnected is not a reason
|
||||
to fall back; complete its client-specific authentication flow first.
|
||||
|
||||
1. Grab a key at https://console.agentkey.app/
|
||||
2. Paste this into the agent's MCP config (path varies per agent):
|
||||
|
||||
@@ -18,12 +18,15 @@ assert manifest["description"]
|
||||
assert manifest["mcpServers"] == {
|
||||
"agentkey": {
|
||||
"httpUrl": "https://api.agentkey.app/v1/mcp",
|
||||
"oauth": {
|
||||
"enabled": True,
|
||||
},
|
||||
}
|
||||
}
|
||||
PY
|
||||
}
|
||||
|
||||
@test "Gemini extension relies on native OAuth discovery" {
|
||||
@test "Gemini extension requests native OAuth while relying on dynamic discovery" {
|
||||
python3 - "$MANIFEST" <<'PY'
|
||||
import json
|
||||
import sys
|
||||
@@ -34,7 +37,11 @@ with open(sys.argv[1], encoding="utf-8") as handle:
|
||||
assert "settings" not in manifest
|
||||
server = manifest["mcpServers"]["agentkey"]
|
||||
assert "headers" not in server
|
||||
assert "oauth" not in server
|
||||
assert server["oauth"] == {"enabled": True}
|
||||
assert "authorizationUrl" not in server["oauth"]
|
||||
assert "tokenUrl" not in server["oauth"]
|
||||
assert "clientId" not in server["oauth"]
|
||||
assert "clientSecret" not in server["oauth"]
|
||||
assert "authProviderType" not in server
|
||||
assert "trust" not in server
|
||||
PY
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
setup() {
|
||||
REPO_ROOT="$(cd "$BATS_TEST_DIRNAME/.." && pwd)"
|
||||
SKILL="$REPO_ROOT/skills/agentkey/SKILL.md"
|
||||
SETUP_GUIDE="$REPO_ROOT/skills/agentkey/references/setup.md"
|
||||
}
|
||||
|
||||
@test "AgentKey skill authenticates bundled MCP entries before registering another server" {
|
||||
python3 - "$SKILL" <<'PY'
|
||||
import sys
|
||||
|
||||
with open(sys.argv[1], encoding="utf-8") as handle:
|
||||
skill = handle.read()
|
||||
|
||||
assert "Authenticate the bundled entry" in skill
|
||||
assert "do not register a duplicate server" in skill
|
||||
assert "do not run the standalone AgentKey CLI" in skill
|
||||
PY
|
||||
}
|
||||
|
||||
@test "Gemini extension setup gives an explicit OAuth and verification flow" {
|
||||
python3 - "$SETUP_GUIDE" <<'PY'
|
||||
import sys
|
||||
|
||||
with open(sys.argv[1], encoding="utf-8") as handle:
|
||||
guide = " ".join(handle.read().split())
|
||||
|
||||
for expected in (
|
||||
"### Gemini CLI extension",
|
||||
"/extensions list",
|
||||
"extension's `oauth.enabled` setting asks Gemini to start its native browser authorization automatically",
|
||||
"/mcp auth agentkey",
|
||||
"/mcp reload",
|
||||
"/mcp list",
|
||||
"Gemini gives user skills higher precedence than extension skills",
|
||||
):
|
||||
assert expected in guide, expected
|
||||
PY
|
||||
}
|
||||
|
||||
@test "Antigravity setup gives desktop and CLI OAuth flows without credentials" {
|
||||
python3 - "$SETUP_GUIDE" <<'PY'
|
||||
import sys
|
||||
|
||||
with open(sys.argv[1], encoding="utf-8") as handle:
|
||||
guide = " ".join(handle.read().split())
|
||||
|
||||
for expected in (
|
||||
"### Antigravity plugin",
|
||||
"Settings → Customizations → Installed MCP Servers",
|
||||
"click **Authenticate** next to AgentKey",
|
||||
"**Antigravity CLI:** open `/mcp`",
|
||||
"dynamic client registration",
|
||||
"Do not put OAuth client secrets, access tokens, or an `Authorization` header",
|
||||
):
|
||||
assert expected in guide, expected
|
||||
PY
|
||||
}
|
||||
|
||||
@test "English and Chinese public docs mirror both client auth flows" {
|
||||
python3 - "$REPO_ROOT/README.md" "$REPO_ROOT/docs/README_zh.md" <<'PY'
|
||||
import sys
|
||||
|
||||
for path in sys.argv[1:]:
|
||||
with open(path, encoding="utf-8") as handle:
|
||||
readme = " ".join(handle.read().split())
|
||||
|
||||
for expected in (
|
||||
"/mcp auth agentkey",
|
||||
"/mcp reload",
|
||||
"/mcp list",
|
||||
"gemini skills uninstall agentkey --scope user",
|
||||
"Settings → Customizations → Installed MCP Servers",
|
||||
"dynamic registration endpoint",
|
||||
):
|
||||
assert expected in readme, f"{path}: {expected}"
|
||||
PY
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
setup_file() {
|
||||
local repo_root
|
||||
repo_root="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
||||
"$repo_root/scripts/build-release-assets.sh" "$BATS_FILE_TMPDIR/assets"
|
||||
}
|
||||
|
||||
setup() {
|
||||
REPO_ROOT="$(cd "$BATS_TEST_DIRNAME/.." && pwd)"
|
||||
ASSET_DIR="$BATS_FILE_TMPDIR/assets"
|
||||
}
|
||||
|
||||
@test "release build preserves the Skill asset" {
|
||||
[ -f "$ASSET_DIR/agentkey.skill" ]
|
||||
|
||||
run unzip -Z1 "$ASSET_DIR/agentkey.skill"
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"SKILL.md"* ]]
|
||||
[[ "$output" == *"scripts/check-update.sh"* ]]
|
||||
}
|
||||
|
||||
@test "release build creates a Gemini archive for every supported platform" {
|
||||
[ -f "$ASSET_DIR/darwin.agentkey.tar.gz" ]
|
||||
[ -f "$ASSET_DIR/linux.agentkey.tar.gz" ]
|
||||
[ -f "$ASSET_DIR/win32.agentkey.zip" ]
|
||||
|
||||
run cmp "$ASSET_DIR/darwin.agentkey.tar.gz" "$ASSET_DIR/linux.agentkey.tar.gz"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "Gemini release archives expose the manifest and Skill at their roots" {
|
||||
for archive_name in darwin.agentkey.tar.gz linux.agentkey.tar.gz; do
|
||||
run tar -tzf "$ASSET_DIR/$archive_name"
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"gemini-extension.json"* ]]
|
||||
[[ "$output" == *"skills/agentkey/SKILL.md"* ]]
|
||||
done
|
||||
|
||||
run unzip -Z1 "$ASSET_DIR/win32.agentkey.zip"
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"gemini-extension.json"* ]]
|
||||
[[ "$output" == *"skills/agentkey/SKILL.md"* ]]
|
||||
}
|
||||
Reference in New Issue
Block a user