diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index ac81921..eac673d 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -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 diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 2c28aa3..b6b359c 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -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 diff --git a/.github/workflows/scripts-test.yml b/.github/workflows/scripts-test.yml index 8c8db60..306b6eb 100644 --- a/.github/workflows/scripts-test.yml +++ b/.github/workflows/scripts-test.yml @@ -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: diff --git a/AGENTS.md b/AGENTS.md index e5f2959..1c1fe06 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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 diff --git a/README.md b/README.md index 416159a..5ed7c70 100644 --- a/README.md +++ b/README.md @@ -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`. diff --git a/docs/README_zh.md b/docs/README_zh.md index 45d91d0..3df3775 100644 --- a/docs/README_zh.md +++ b/docs/README_zh.md @@ -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 扩展压缩包。 diff --git a/gemini-extension.json b/gemini-extension.json index 451088e..11cb638 100644 --- a/gemini-extension.json +++ b/gemini-extension.json @@ -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 + } } } } diff --git a/scripts/build-release-assets.sh b/scripts/build-release-assets.sh new file mode 100755 index 0000000..4f4e89e --- /dev/null +++ b/scripts/build-release-assets.sh @@ -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 diff --git a/skills/agentkey/SKILL.md b/skills/agentkey/SKILL.md index ab68011..3acb94e 100644 --- a/skills/agentkey/SKILL.md +++ b/skills/agentkey/SKILL.md @@ -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: diff --git a/skills/agentkey/references/setup.md b/skills/agentkey/references/setup.md index f9d1c4a..89bacc5 100644 --- a/skills/agentkey/references/setup.md +++ b/skills/agentkey/references/setup.md @@ -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): diff --git a/tests/gemini-extension.bats b/tests/gemini-extension.bats index 01104e9..af5c27f 100644 --- a/tests/gemini-extension.bats +++ b/tests/gemini-extension.bats @@ -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 diff --git a/tests/plugin-auth-guidance.bats b/tests/plugin-auth-guidance.bats new file mode 100644 index 0000000..c2199fd --- /dev/null +++ b/tests/plugin-auth-guidance.bats @@ -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 +} diff --git a/tests/release-assets.bats b/tests/release-assets.bats new file mode 100644 index 0000000..5fe89ed --- /dev/null +++ b/tests/release-assets.bats @@ -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"* ]] +}