diff --git a/skills/scripts/refresh-tool-index.sh b/skills/scripts/refresh-tool-index.sh index 578fb41..daafe4f 100644 --- a/skills/scripts/refresh-tool-index.sh +++ b/skills/scripts/refresh-tool-index.sh @@ -129,12 +129,11 @@ TOOLS=( "nuclei|pentest-tools|Template-based vulnerability scanner|nuclei|nuclei -version|" "binwalk|firmware-pentest|Firmware extraction and analysis|binwalk|binwalk --version|" "seclists|pentest-tools|Security wordlists|none|none|$HOME/tools/SecLists;/usr/share/seclists" - "jshookmcp|js-reverse|JS/CDP/Hook MCP runtime via npx|npx|npx --version|" - "reqable-mcp|pentest-tools|Reqable desktop MCP runtime via npx|npx|npx --version|" + "jshookmcp|js-reverse|JS/CDP/Hook MCP capability (requires registration + npx runtime)|none|none|" + "reqable-mcp|pentest-tools|Reqable MCP capability (requires registration + npx runtime)|none|none|" "jeb-pro|apk-reverse|Commercial Android/ARM decompiler (manual licensed install)|jeb,jeb_wincon|jeb --version|$HOME/tools/JEB/jeb;$HOME/JEB/jeb;/opt/jeb/jeb" "anything-analyzer|browser-automation|Browser/HTTP analyzer MCP project|none|none|$HOME/tools/anything-analyzer;$REPO_ROOT/../anything-analyzer" "burp-mcp-full|burp-mcp|Local Burp MCP extension and stdio bridge|none|none|$REPO_ROOT/burp-mcp-full/mcp-bridge.js" - "binwalk|firmware-pentest|Firmware extraction and analysis|binwalk|binwalk --version|" "yara|malware-analysis|Malware rule matching engine|yara|yara --version|" "pwntools|reverse-engineering|CTF pwn exploit development framework|pwn|pwn --version|" ) @@ -224,41 +223,40 @@ done } >> "$OUTPUT_MD" # --- Capability status view ------------------------------------------------- -# Parity with skills/scripts/refresh-tool-index.ps1 (the "能力状态视图" block). -# Computed by parsing skills/scripts/bootstrap-manifest.json plus probing the -# local MCP config and each declared servicePort. All logic is contained in the -# Python heredoc below so this script keeps its existing bash dependencies. +# Parity with skills/scripts/refresh-tool-index.ps1. Registration is discovered +# across supported host adapters rather than assuming one default AI client. MANIFEST_PATH="$SCRIPT_DIR/bootstrap-manifest.json" -MCP_CONFIG_PATH_FOR_CAP="${CLAUDE_MCP_CONFIG:-$HOME/.claude/mcp.json}" +CLAUDE_MCP_CONFIG_PATH_FOR_CAP="${CLAUDE_MCP_CONFIG:-$HOME/.claude/mcp.json}" +CODEX_MCP_CONFIG_PATH_FOR_CAP="${CODEX_CONFIG_PATH:-$HOME/.codex/config.toml}" CAP_RECORDS_TMP="$(mktemp)" -# Replace earlier single-file trap with one that also cleans this capability tmp file. trap 'rm -f "$records_tmp" "$CAP_RECORDS_TMP"' EXIT if [[ -f "$MANIFEST_PATH" ]]; then - # Pass tool availability info (collected earlier) so the capability view can - # reflect the same "tool ready" judgement as the tool table above. - python3 - "$MANIFEST_PATH" "$MCP_CONFIG_PATH_FOR_CAP" "$records_tmp" "$CAP_RECORDS_TMP" <<'PY' -import json, pathlib, socket, sys, urllib.request + python3 - "$MANIFEST_PATH" "$CLAUDE_MCP_CONFIG_PATH_FOR_CAP" "$CODEX_MCP_CONFIG_PATH_FOR_CAP" "$records_tmp" "$CAP_RECORDS_TMP" <<'PY' +import json, pathlib, re, socket, sys, urllib.request -manifest_path, mcp_config_path, tool_records_path, out_path = sys.argv[1:5] +manifest_path, claude_config_path, codex_config_path, tool_records_path, out_path = sys.argv[1:6] -# Load capability definitions try: manifest = json.loads(pathlib.Path(manifest_path).read_text(encoding='utf-8')) except Exception: manifest = {'capabilities': []} capabilities = manifest.get('capabilities', []) -# Load currently registered MCP server names registered_names = set() try: - mcp_data = json.loads(pathlib.Path(mcp_config_path).read_text(encoding='utf-8')) - registered_names = set(mcp_data.get('mcpServers', {}).keys()) + mcp_data = json.loads(pathlib.Path(claude_config_path).read_text(encoding='utf-8')) + registered_names.update(mcp_data.get('mcpServers', {}).keys()) +except Exception: + pass +try: + codex_text = pathlib.Path(codex_config_path).read_text(encoding='utf-8') + pattern = re.compile(r'^\s*\[mcp_servers\.([^\].]+)\]\s*$', re.MULTILINE) + registered_names.update(pattern.findall(codex_text)) except Exception: pass -# Load tool availability from the table we already wrote (best-effort match by name) tool_available = {} try: with open(tool_records_path, encoding='utf-8') as f: @@ -311,6 +309,7 @@ for cap in capabilities: mcp_http_verified = mcp_http_handshake(service_port) tool_ready = bool(tool_available.get(name, False)) + runtime_ready = bool(tool_available.get('npx', False)) if bootstrap_kind == 'npm-mcp' else tool_ready if mcp_names: if verification_mode == 'service-and-registration': @@ -318,7 +317,7 @@ for cap in capabilities: elif verification_mode == 'service-or-registration': ready = registered or service_online elif bootstrap_kind == 'npm-mcp': - ready = registered and tool_ready + ready = registered and runtime_ready else: ready = registered or tool_ready else: @@ -327,6 +326,7 @@ for cap in capabilities: rows.append({ 'name': name, 'tool_available': tool_ready, + 'runtime_available': runtime_ready, 'ready': ready, 'mcp_registered': registered if mcp_names else None, 'service_online': service_online if service_port else None, @@ -339,7 +339,6 @@ with open(out_path, 'w', encoding='utf-8') as f: json.dump(rows, f, ensure_ascii=False) PY - # Append the markdown capability table (mirrors the headings used in the ps1 version) { echo "" echo "---" @@ -353,9 +352,9 @@ PY python3 - "$CAP_RECORDS_TMP" "$OUTPUT_MD" <<'PY' import json, sys rows = json.loads(open(sys.argv[1], encoding='utf-8').read()) -def yn(v): # True->✓, False->✗ +def yn(v): return '✓' if v else '✗' -def opt(v): # True->✓, False->—, None->— +def opt(v): if v is True: return '✓' if v is False: return '—' return '—' @@ -367,7 +366,7 @@ with open(sys.argv[2], 'a', encoding='utf-8') as out: f"{opt(r['mcp_http_verified'])} | {yn(r['can_auto_install'])} | " f"{r['bootstrap_kind'] or '—'} |\n" ) - out.write("\n> ✓ = 是 | ✗ = 否 | — = 不适用或未检测\n\n") + out.write("\n> ✓ = 是 | ✗ = 否 | — = 不适用或未检测。npm-mcp 的 Ready 使用 MCP 注册状态 + npx runtime;npx 本身不会让某个 MCP capability 变成工具可用。\n\n") PY else CAP_RECORDS_TMP=""