From 53334988a4639cbfed3b57fb11d32ba8aac193d9 Mon Sep 17 00:00:00 2001 From: CabLate <85614048+cablate@users.noreply.github.com> Date: Sun, 27 Sep 2026 02:33:26 +0800 Subject: [PATCH] feat: package CLI skill as installable plugin --- .agents/plugins/marketplace.json | 22 +++++++ .../skills}/project-docs/SKILL.md | 0 .../project-docs/references/architecture.md | 0 .../project-docs/references/decisions.md | 0 .../references/geo-domain-knowledge.md | 0 .../references/google-maps-api-guide.md | 0 .codex-plugin/plugin.json | 28 ++++++++ .github/workflows/release.yml | 8 ++- .gitignore | 7 +- README.md | 25 +++++--- README.zh-TW.md | 25 +++++--- package.json | 2 + plugin.json | 14 ++++ skills/google-maps/SKILL.md | 2 - skills/google-maps/SKILL.skill | Bin 19972 -> 19890 bytes tests/pluginPackage.unit.test.ts | 60 ++++++++++++++++++ 16 files changed, 172 insertions(+), 21 deletions(-) create mode 100644 .agents/plugins/marketplace.json rename {skills => .agents/skills}/project-docs/SKILL.md (100%) rename {skills => .agents/skills}/project-docs/references/architecture.md (100%) rename {skills => .agents/skills}/project-docs/references/decisions.md (100%) rename {skills => .agents/skills}/project-docs/references/geo-domain-knowledge.md (100%) rename {skills => .agents/skills}/project-docs/references/google-maps-api-guide.md (100%) create mode 100644 .codex-plugin/plugin.json create mode 100644 plugin.json create mode 100644 tests/pluginPackage.unit.test.ts diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json new file mode 100644 index 0000000..c8e8800 --- /dev/null +++ b/.agents/plugins/marketplace.json @@ -0,0 +1,22 @@ +{ + "name": "cablate", + "interface": { + "displayName": "CabLate Plugins" + }, + "plugins": [ + { + "name": "mcp-google-map", + "source": { + "source": "npm", + "package": "@cablate/mcp-google-map", + "version": "latest", + "registry": "https://registry.npmjs.org" + }, + "policy": { + "installation": "AVAILABLE", + "authentication": "ON_INSTALL" + }, + "category": "Productivity" + } + ] +} diff --git a/skills/project-docs/SKILL.md b/.agents/skills/project-docs/SKILL.md similarity index 100% rename from skills/project-docs/SKILL.md rename to .agents/skills/project-docs/SKILL.md diff --git a/skills/project-docs/references/architecture.md b/.agents/skills/project-docs/references/architecture.md similarity index 100% rename from skills/project-docs/references/architecture.md rename to .agents/skills/project-docs/references/architecture.md diff --git a/skills/project-docs/references/decisions.md b/.agents/skills/project-docs/references/decisions.md similarity index 100% rename from skills/project-docs/references/decisions.md rename to .agents/skills/project-docs/references/decisions.md diff --git a/skills/project-docs/references/geo-domain-knowledge.md b/.agents/skills/project-docs/references/geo-domain-knowledge.md similarity index 100% rename from skills/project-docs/references/geo-domain-knowledge.md rename to .agents/skills/project-docs/references/geo-domain-knowledge.md diff --git a/skills/project-docs/references/google-maps-api-guide.md b/.agents/skills/project-docs/references/google-maps-api-guide.md similarity index 100% rename from skills/project-docs/references/google-maps-api-guide.md rename to .agents/skills/project-docs/references/google-maps-api-guide.md diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json new file mode 100644 index 0000000..d12a6be --- /dev/null +++ b/.codex-plugin/plugin.json @@ -0,0 +1,28 @@ +{ + "name": "mcp-google-map", + "version": "0.0.63", + "description": "Use Google Maps-backed place search, routing, geocoding, weather, air quality, and geographic analysis through a standalone CLI.", + "author": { + "name": "CabLate", + "url": "https://github.com/cablate" + }, + "homepage": "https://github.com/cablate/mcp-google-map", + "repository": "https://github.com/cablate/mcp-google-map", + "license": "MIT", + "keywords": ["google-maps", "places", "routing", "geocoding", "travel", "agent-skill"], + "skills": "./skills/", + "interface": { + "displayName": "Google Maps CLI", + "shortDescription": "Geospatial research and planning through a standalone CLI.", + "longDescription": "Guide an AI agent to use the @cablate/mcp-google-map exec CLI for place discovery, routing, geocoding, travel planning, local SEO, weather, air quality, and other geographic workflows. No MCP connection is required.", + "developerName": "CabLate", + "category": "Productivity", + "capabilities": ["Read"], + "websiteURL": "https://github.com/cablate/mcp-google-map", + "defaultPrompt": [ + "Find and compare places for my trip.", + "Plan an efficient route between these stops.", + "Research what is near this location." + ] + } +} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 928d879..554d635 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -65,7 +65,11 @@ jobs: git pull --rebase - name: Bump version - run: npm version patch --no-git-tag-version + run: | + npm version patch --no-git-tag-version + VERSION=$(node -p "require('./package.json').version") + jq --arg v "$VERSION" '.version = $v' plugin.json > plugin.tmp && mv plugin.tmp plugin.json + jq --arg v "$VERSION" '.version = $v' .codex-plugin/plugin.json > plugin.tmp && mv plugin.tmp .codex-plugin/plugin.json - name: Update CHANGELOG run: | @@ -161,7 +165,7 @@ jobs: - name: Commit version bump & tag run: | VERSION=$(node -p "require('./package.json').version") - git add package.json package-lock.json CHANGELOG.md server.json + git add package.json package-lock.json CHANGELOG.md server.json plugin.json .codex-plugin/plugin.json git commit -m "chore: release v${VERSION}" git tag "v${VERSION}" git pull --rebase diff --git a/.gitignore b/.gitignore index d420094..371d6f8 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,11 @@ node_modules/ credentials.json .env .agents/* +!.agents/plugins/ +!.agents/plugins/marketplace.json +!.agents/skills/ +!.agents/skills/project-docs/ +!.agents/skills/project-docs/** .mcpregistry_* .mcp.json -output/ \ No newline at end of file +output/ diff --git a/README.md b/README.md index 27e5ba4..cab6e61 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,17 @@ All tools are annotated with `readOnlyHint: true` and `destructiveHint: false` ## Installation +### Codex Plugin (Agent Skill, no MCP required) + +Install the CabLate marketplace, then install the Skill-only plugin: + +```bash +codex plugin marketplace add cablate/mcp-google-map --ref main +codex plugin add mcp-google-map@cablate +``` + +Set `GOOGLE_MAPS_API_KEY` in the environment available to Codex, make sure Node.js 18+ and `npx` are installed, then start a new conversation. The plugin teaches the agent to run `npx -y @cablate/mcp-google-map exec ...` directly. It does not register or start an MCP server; the MCP setup below remains an independent option. + ### Method 1: stdio (Recommended for most clients) Works with Claude Desktop, Cursor, VS Code, and any MCP client that supports stdio: @@ -290,20 +301,18 @@ src/ tests/ └── smoke.test.ts # Smoke + E2E test suite skills/ -├── google-maps/ # Agent Skill — how to USE the tools +└── google-maps/ # Public Agent Skill — standalone CLI workflows │ ├── SKILL.md # Tool map, recipes, invocation │ ├── SKILL.skill # Importable archive of this Skill │ └── references/ │ ├── tools-api.md # Tool parameters + scenario recipes │ ├── travel-planning.md # Travel planning methodology │ └── local-seo.md # Local SEO / Google Business Profile ranking analysis -└── project-docs/ # Project Skill — how to DEVELOP/MAINTAIN - ├── SKILL.md # Architecture overview + onboarding - └── references/ - ├── architecture.md # System design, code map, 9-file checklist - ├── google-maps-api-guide.md # API endpoints, pricing, gotchas - ├── geo-domain-knowledge.md # GIS fundamentals, Japan context - └── decisions.md # 10 ADRs (design decisions + rationale) +.agents/ +├── plugins/marketplace.json # CabLate marketplace catalog +└── skills/project-docs/ # Maintainer-only development Skill +.codex-plugin/plugin.json # Codex compatibility manifest +plugin.json # Portable Agent Plugin manifest ``` ## Tech Stack diff --git a/README.zh-TW.md b/README.zh-TW.md index fa38004..9b6c9b2 100644 --- a/README.zh-TW.md +++ b/README.zh-TW.md @@ -89,6 +89,17 @@ npx @cablate/mcp-google-map --port 3000 --apikey "YOUR_API_KEY" ## 安裝 +### Codex Plugin(Agent Skill,不需要 MCP) + +先加入 CabLate marketplace,再安裝只包含 Skill 的 plugin: + +```bash +codex plugin marketplace add cablate/mcp-google-map --ref main +codex plugin add mcp-google-map@cablate +``` + +請在 Codex 可讀取的環境中設定 `GOOGLE_MAPS_API_KEY`,並確認已安裝 Node.js 18+ 與 `npx`,然後開啟新對話。Plugin 會教代理直接執行 `npx -y @cablate/mcp-google-map exec ...`;它不會註冊或啟動 MCP server。下方的 MCP 設定仍是另一種獨立使用方式。 + ### 方法一:stdio(大多數客戶端推薦) 適用於 Claude Desktop、Cursor、VS Code 及任何支援 stdio 的 MCP 客戶端: @@ -287,20 +298,18 @@ src/ tests/ └── smoke.test.ts # Smoke + E2E 測試套件 skills/ -├── google-maps/ # Agent Skill — 如何使用工具 +└── google-maps/ # 公開 Agent Skill — 獨立 CLI 工作流程 │ ├── SKILL.md # 工具對照表、場景食譜、呼叫方式 │ ├── SKILL.skill # 可匯入的 Skill 封裝檔 │ └── references/ │ ├── tools-api.md # 工具參數 + 場景食譜 │ ├── travel-planning.md # 旅行規劃方法論 │ └── local-seo.md # Local SEO / Google 商家排名分析 -└── project-docs/ # Project Skill — 如何開發/維護 - ├── SKILL.md # 架構概覽 + 入門指南 - └── references/ - ├── architecture.md # 系統設計、code map、9 檔案 checklist - ├── google-maps-api-guide.md # API 端點、定價、注意事項 - ├── geo-domain-knowledge.md # GIS 基礎、日本場景 - └── decisions.md # 10 個 ADR(設計決策 + 理由) +.agents/ +├── plugins/marketplace.json # CabLate marketplace 目錄 +└── skills/project-docs/ # 僅供維護者使用的開發 Skill +.codex-plugin/plugin.json # Codex 相容 manifest +plugin.json # 可攜式 Agent Plugin manifest ``` ## 技術棧 diff --git a/package.json b/package.json index 5c8b889..88ed1a3 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,8 @@ "dist", "dist/**/*.map", "README.md", + "plugin.json", + ".codex-plugin", "skills", "examples" ], diff --git a/plugin.json b/plugin.json new file mode 100644 index 0000000..9967bc0 --- /dev/null +++ b/plugin.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", + "name": "mcp-google-map", + "version": "0.0.63", + "description": "Use Google Maps-backed place search, routing, geocoding, weather, air quality, and geographic analysis through a standalone CLI.", + "author": { + "name": "CabLate", + "url": "https://github.com/cablate" + }, + "homepage": "https://github.com/cablate/mcp-google-map", + "repository": "https://github.com/cablate/mcp-google-map", + "license": "MIT", + "keywords": ["google-maps", "places", "routing", "geocoding", "travel", "agent-skill"] +} diff --git a/skills/google-maps/SKILL.md b/skills/google-maps/SKILL.md index 9186156..6bd5a7c 100644 --- a/skills/google-maps/SKILL.md +++ b/skills/google-maps/SKILL.md @@ -111,5 +111,3 @@ npx -y @cablate/mcp-google-map exec '' | `references/travel-planning.md` | Travel planning methodology — 6-layer model, Search Along Route, anti-patterns | When planning multi-day trips — **read before Recipe 1** | | `references/local-seo.md` | Local SEO / Google Business Profile ranking analysis — competitor audit, keyword landscape, gap analysis | When analyzing business rankings, comparing competitors, or scouting locations | | `references/content-attribution.md` | Google Maps content attribution, source links, AI disclosure, and storage limits | Before presenting reviews, photos, or AI summaries from Places | - -> For **project development** knowledge (architecture, API guide, GIS domain, design decisions), see `skills/project-docs/SKILL.md`. diff --git a/skills/google-maps/SKILL.skill b/skills/google-maps/SKILL.skill index b901dca021df73b409af4b86084b9c9f77758760..8efa885270a43921768210eff317011a0eca1b98 100644 GIT binary patch delta 2916 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 diff --git a/tests/pluginPackage.unit.test.ts b/tests/pluginPackage.unit.test.ts new file mode 100644 index 0000000..5f3e4b5 --- /dev/null +++ b/tests/pluginPackage.unit.test.ts @@ -0,0 +1,60 @@ +import assert from "node:assert/strict"; +import { readFileSync } from "node:fs"; +import test from "node:test"; + +interface PluginManifest { + name: string; + version: string; + skills?: string; + mcpServers?: unknown; +} + +interface PackageManifest { + version: string; + files: string[]; +} + +interface Marketplace { + name: string; + plugins: Array<{ + name: string; + source: Record; + policy: { installation: string; authentication: string }; + }>; +} + +function readJson(path: string): T { + return JSON.parse(readFileSync(new URL(`../${path}`, import.meta.url), "utf8")) as T; +} + +test("plugin package is Skill-only and versioned with the npm package", () => { + const packageJson = readJson("package.json"); + const portableManifest = readJson("plugin.json"); + const codexManifest = readJson(".codex-plugin/plugin.json"); + + assert.equal(portableManifest.name, "mcp-google-map"); + assert.equal(codexManifest.name, portableManifest.name); + assert.equal(portableManifest.version, packageJson.version); + assert.equal(codexManifest.version, packageJson.version); + assert.equal(codexManifest.skills, "./skills/"); + assert.equal("mcpServers" in portableManifest, false); + assert.equal("mcpServers" in codexManifest, false); + assert.ok(packageJson.files.includes("plugin.json")); + assert.ok(packageJson.files.includes(".codex-plugin")); +}); + +test("CabLate marketplace installs the published npm plugin", () => { + const marketplace = readJson(".agents/plugins/marketplace.json"); + const [plugin] = marketplace.plugins; + + assert.equal(marketplace.name, "cablate"); + assert.equal(plugin.name, "mcp-google-map"); + assert.deepEqual(plugin.source, { + source: "npm", + package: "@cablate/mcp-google-map", + version: "latest", + registry: "https://registry.npmjs.org", + }); + assert.equal(plugin.policy.installation, "AVAILABLE"); + assert.equal(plugin.policy.authentication, "ON_INSTALL"); +});