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 b901dca..8efa885 100644 Binary files a/skills/google-maps/SKILL.skill and b/skills/google-maps/SKILL.skill differ 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"); +});