npx claudepluginhub psychquant/psychquant-claude-plugins --plugin mcp-toolsThis skill uses the workspace's default tool permissions.
---
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
把一個已存在的 MCP Server 轉換成標準 Claude Code Plugin,包含自動下載 wrapper、macOS Keychain 密鑰管理、session start hook、以及 command/skill 骨架。
MCP Server 直接寫在 ~/.claude.json 有幾個問題:
Plugin 解決以上所有問題:wrapper script 從 Keychain 讀密鑰、hook 自動檢查安裝狀態、commands 提供快捷操作、skills 提供使用指南。
開始之前,需要確定以下資訊。如果能從 ~/.claude.json 或專案目錄自動偵測就用偵測的,偵測不到的用 AskUserQuestion 問。
情境 A:用戶指定了一個已在 ~/.claude.json 中設定的 MCP
# 從 ~/.claude.json 讀取 MCP 設定
cat ~/.claude.json | python3 -c "
import json, sys
d = json.load(sys.stdin)
for name, cfg in d.get('mcpServers', {}).items():
print(f'{name}: {json.dumps(cfg, indent=2)}')
"
從中提取:
mcp_name — MCP 名稱(如 che-telegram-all-mcp)binary_path — binary 路徑env_vars — 環境變數(這些就是要移到 Keychain 的密鑰)情境 B:用戶指定了一個本機專案目錄
# 偵測 binary 名稱和 GitHub repo
ls Package.swift pyproject.toml package.json 2>/dev/null # 偵測語言
gh repo view --json nameWithOwner -q '.nameWithOwner' 2>/dev/null # GitHub repo
用 AskUserQuestion 確認(如果無法自動偵測):
| 參數 | 說明 | 範例 |
|---|---|---|
plugin_name | Plugin 目錄名 | che-telegram-mcp |
github_repo | GitHub owner/repo | kiki830621/che-telegram-all-mcp |
binary_name | 執行檔名稱 | CheTelegramAllMCP |
description | 簡短描述 | Telegram 全功能 MCP Server |
env_vars | 需要的環境變數列表 | TELEGRAM_API_ID, TELEGRAM_API_HASH |
keychain_account | Keychain 帳號名稱 | 通常跟 mcp_name 一樣 |
如果用戶想把多個相關的 MCP Server 合併成一個 Plugin(例如 telegram-bot + telegram-all),確認:
Note: Plugin 基礎結構(目錄、plugin.json、CLAUDE.md、marketplace.json)也可以用
/plugin-tools:plugin-create {plugin_name}一鍵建立。本 phase 保留手動步驟是因為 MCP plugin 需要額外的bin/和.mcp.json,plugin-create 不會自動建這些。
Plugin 目標路徑:marketplace repo 下的 plugins/{plugin_name}/
PLUGIN_DIR="$MARKETPLACE_ROOT/plugins/{plugin_name}"
mkdir -p "$PLUGIN_DIR/.claude-plugin"
mkdir -p "$PLUGIN_DIR/bin"
mkdir -p "$PLUGIN_DIR/commands"
mkdir -p "$PLUGIN_DIR/hooks"
mkdir -p "$PLUGIN_DIR/skills/{skill_name}"
.claude-plugin/plugin.json{
"name": "{plugin_name}",
"version": "1.0.0",
"description": "{description}",
"author": { "name": "Che Cheng" },
"license": "MIT",
"keywords": ["mcp", "{relevant}", "{keywords}"]
}
.mcp.json單一 MCP:
{
"{server_id}": {
"type": "stdio",
"command": "${CLAUDE_PLUGIN_ROOT}/bin/{plugin_name}-wrapper.sh",
"description": "{description}"
}
}
多 MCP(合併情境):
{
"{server_id_1}": {
"type": "stdio",
"command": "${CLAUDE_PLUGIN_ROOT}/bin/{mcp1}-wrapper.sh",
"description": "{description_1}"
},
"{server_id_2}": {
"type": "stdio",
"command": "${CLAUDE_PLUGIN_ROOT}/bin/{mcp2}-wrapper.sh",
"description": "{description_2}"
}
}
server_id 是 MCP 在 Claude Code 裡的識別名(出現在 tool 名稱前綴),應該簡短有意義。
這是轉換的核心價值 — 把 ~/.claude.json 裡的明文密鑰移到 macOS Keychain。
對每個環境變數執行:
security add-generic-password \
-a "{keychain_account}" \
-s "{ENV_VAR_NAME}" \
-w "{secret_value}" \
-U
-a (account) 用 MCP 名稱分組,-s (service) 用環境變數名,-U 表示如果已存在就更新。
security find-generic-password -a "{keychain_account}" -s "{ENV_VAR_NAME}" -w
告知用戶:
Wrapper script 的職責:找到 binary → 從 Keychain 讀密鑰 → 啟動 MCP。
#!/bin/bash
# Auto-download wrapper for {binary_name}
REPO="{github_repo}"
BINARY_NAME="{binary_name}"
INSTALL_DIR="$HOME/bin"
# Find binary
BINARY=""
for loc in "$INSTALL_DIR/$BINARY_NAME" "/usr/local/bin/$BINARY_NAME" "$HOME/.local/bin/$BINARY_NAME"; do
[[ -x "$loc" ]] && BINARY="$loc" && break
done
if [[ -z "$BINARY" ]]; then
echo "$BINARY_NAME not found. Downloading from GitHub..." >&2
mkdir -p "$INSTALL_DIR"
URL=$(curl -sL "https://api.github.com/repos/$REPO/releases/latest" \
| grep '"browser_download_url"' | grep "$BINARY_NAME" | head -1 \
| sed 's/.*"\(https[^"]*\)".*/\1/')
if [[ -n "$URL" ]]; then
curl -sL "$URL" -o "$INSTALL_DIR/$BINARY_NAME" && chmod +x "$INSTALL_DIR/$BINARY_NAME" \
|| { echo "ERROR: Download failed." >&2; exit 1; }
BINARY="$INSTALL_DIR/$BINARY_NAME"
echo "Installed $BINARY_NAME to $INSTALL_DIR/" >&2
else
echo "No release found. Build from source: https://github.com/$REPO" >&2
exit 1
fi
fi
# Read credentials from macOS Keychain
{keychain_exports}
{keychain_validation}
exec "$BINARY" "$@"
跟模板 A 類似,但 binary 搜尋路徑多加 build 目錄,找不到時提示 build 指令而非自動下載:
# 額外搜尋 build 目錄
for loc in ... "$HOME/Developer/che-mcps/{repo_name}/.build/release/$BINARY_NAME"; do
找不到時:
echo "Build from source:" >&2
echo " git clone https://github.com/$REPO.git" >&2
echo " cd {repo_name} && swift build -c release" >&2
對每個環境變數生成:
export {ENV_VAR}="$(security find-generic-password -a "{keychain_account}" -s "{ENV_VAR}" -w 2>/dev/null)"
驗證區塊:
if [[ -z "${ENV_VAR_1}" || -z "${ENV_VAR_2}" ]]; then
echo "Credentials not found in Keychain. Set them up:" >&2
echo " security add-generic-password -a {keychain_account} -s {ENV_VAR_1} -w 'VALUE' -U" >&2
echo " security add-generic-password -a {keychain_account} -s {ENV_VAR_2} -w 'VALUE' -U" >&2
exit 1
fi
設定 executable 權限:
chmod +x "$PLUGIN_DIR/bin/"*.sh
Hook 在每次 Claude Code 啟動時檢查 MCP 安裝狀態和 Keychain 密鑰。
{
"hooks": {
"SessionStart": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/check-mcp.sh"
}
]
}
}
為每個 MCP 生成檢查區塊:
#!/bin/bash
check_binary() {
local name="$1" repo="$2" label="$3"
local found=false
for loc in "$HOME/bin/$name" "/usr/local/bin/$name" "$HOME/.local/bin/$name" "$HOME/Developer/che-mcps/$(echo "$repo" | cut -d/ -f2)/.build/release/$name"; do
[[ -x "$loc" ]] && found=true && break
done
if [[ "$found" == "true" ]]; then
echo "✓ $label installed"
else
echo "⚠️ $label not found"
echo " Install: https://github.com/$repo"
fi
}
check_keychain() {
local account="$1" service="$2" label="$3"
if security find-generic-password -a "$account" -s "$service" -w &>/dev/null; then
echo "✓ $label in Keychain"
else
echo "⚠️ $label not in Keychain"
echo " Run: security add-generic-password -a $account -s $service -w 'VALUE' -U"
fi
}
echo "── {Plugin Name} Status ──"
# 對每個 MCP 生成 check_binary 和 check_keychain 呼叫
記得 chmod +x hooks/check-mcp.sh。
根據 MCP 的工具列表,生成 3-5 個最常用的 slash commands。
從 MCP source code 提取工具名稱:
# Swift MCP
grep -oE 'case "[a-z_]+"' Sources/*/Server.swift | sed 's/case "//;s/"//'
# Python MCP
grep -oE '@server\.tool\("[a-z_]+"' src/*.py | sed 's/@server\.tool("//;s/"//'
# TypeScript MCP
grep -oE 'server\.tool\("[a-z_]+"' src/*.ts | sed 's/server\.tool("//;s/"//'
每個 command 是一個 .md 檔:
---
name: {command_name}
description: {一行描述}
allowed-tools:
- mcp__{plugin_name}__{tool_1}
- mcp__{plugin_name}__{tool_2}
---
# {Command Title}
{使用步驟,2-5 步}
挑選 command 的原則:
建立一個綜合性的 skill,涵蓋所有 MCP 工具的使用指南。
---
name: {skill_name}
description: {觸發描述 — 什麼情況下使用這個 skill}
allowed-tools:
- mcp__{plugin_name}__{tool_1}
- mcp__{plugin_name}__{tool_2}
...
---
# {Skill Title}
## Tool Categories
### 1. Discovery (Start Here)
| Tool | Purpose |
|------|---------|
| ... | ... |
### 2. {Core Operations}
| Tool | Purpose |
|------|---------|
| ... | ... |
## Common Workflows
### {Workflow 1}
步驟...
### {Workflow 2}
步驟...
## Best Practices
1. ...
2. ...
把轉換完成的 MCP 從 ~/.claude.json 移除,因為 Plugin 的 .mcp.json 會接管。
cp ~/.claude.json ~/.claude.json.backup.$(date +%s)
用 Edit 工具從 ~/.claude.json 的 mcpServers 中移除已轉換的 MCP entry。
提醒用戶重啟 Claude Code 後,MCP 會透過 Plugin 載入而非 ~/.claude.json。
# MCP → Plugin 轉換完成
## Plugin 資訊
- 名稱: {plugin_name}
- 位置: $MARKETPLACE_ROOT/plugins/{plugin_name}/
- MCP Servers: {列出所有 server_id}
## 密鑰管理
- 儲存位置: macOS Keychain (Login Keychain)
- 帳號: {keychain_account}
- 密鑰: {列出 ENV_VAR 名稱,不含值}
## 已建立的檔案
- .claude-plugin/plugin.json
- .mcp.json
- bin/{wrapper scripts}
- hooks/hooks.json + check-mcp.sh
- commands/{列出 commands}
- skills/{skill_name}/SKILL.md
- README.md
## 重灌恢復指令
{列出 security add-generic-password 指令,值用 placeholder}
## 下一步
- 重啟 Claude Code 載入新 Plugin
- 測試: 使用 slash commands 驗證功能
- 如需發布到 marketplace: `/plugin-tools:plugin-deploy {plugin_name}`