fix(audit): correct MCP detection to check ~/.claude.json

The audit script was looking for MCP config in ~/.claude/mcp.json which
doesn't exist. Claude Code actually stores MCP config in ~/.claude.json
under projects.<path>.mcpServers.

Changes:
- audit-scan.sh: Multi-source MCP detection (3 locations with priority)
- audit-scan.sh: Fixed count_pattern() bug causing "0\n0" output
- claude-setup-audit-prompt.md: Updated bash commands for MCP detection
- Version bump: 2.8 → 2.9

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Florian BRUNIAUX 2026-01-12 08:37:01 +01:00
parent bafbeae31c
commit 0833e1ca65
4 changed files with 141 additions and 27 deletions

View file

@ -6,6 +6,39 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased]
## [2.9.0] - 2026-01-12
### Fixed
- **MCP detection bug in audit-scan.sh** (~60 lines modified)
- **Root cause**: Script searched for `~/.claude/mcp.json` which doesn't exist
- **Actual location**: Claude Code stores MCP config in `~/.claude.json` under `projects.<path>.mcpServers`
- **Solution**: Multi-source detection with priority:
1. `~/.claude.json``projects.<cwd>.mcpServers` (most common)
2. `./.claude/mcp.json` (project-level)
3. `~/.claude/mcp.json` (legacy global)
- JSON output now includes detailed `mcp` section (configured, count, servers, source)
- Human output shows server count and source location
- **Bug `0\n0` in `claude_md_refs`** (~8 lines)
- **Root cause**: `grep -c ... || echo "0"` could produce double output
- **Solution**: Rewritten `count_pattern()` function to properly capture and return count
### Changed
- **audit-scan.sh** enhanced (~50 lines)
- Added `MCP_SOURCE` variable to track where MCP config was found
- Added `MCP_COUNT` variable for server count
- Global `mcp.json` message changed from error to info (not required)
- JSON output restructured with separate `mcp` object
- **claude-setup-audit-prompt.md** updated (~40 lines)
- Phase 1.1: Now checks `~/.claude.json` instead of `~/.claude/mcp.json`
- Phase 1.2: Complete MCP detection rewrite covering all 3 locations
- Glossary: Updated MCP definition to explain config locations
- Version: 2.8 → 2.9
### Stats
- 2 files modified (audit-scan.sh, claude-setup-audit-prompt.md)
- Bug impact: Scripts now correctly detect MCP servers (was showing "No MCP" even when configured)
- Tested: Verified on Méthode Aristote project with 9 MCP servers
## [2.8.0] - 2026-01-11
### Added

View file

@ -315,7 +315,7 @@ If this guide saved you time, helped you master Claude Code, or inspired your wo
---
*Version 2.8 | January 2026 | Crafted with Claude*
*Version 2.9 | January 2026 | Crafted with Claude*
<!-- SEO Keywords -->
<!-- claude code, claude code tutorial, anthropic cli, ai coding assistant, claude code mcp,

View file

@ -95,9 +95,11 @@ https://github.com/FlorianBruniaux/claude-code-ultimate-guide/blob/main/english-
```bash
bash -c '
echo "=== GLOBAL CONFIG ==="
for f in ~/.claude/CLAUDE.md ~/.claude/settings.json ~/.claude/mcp.json; do
for f in ~/.claude/CLAUDE.md ~/.claude/settings.json; do
[ -f "$f" ] && echo "✅ $(basename $f)" || echo "❌ $(basename $f)"
done
# Note: MCP config is now in ~/.claude.json, not ~/.claude/mcp.json
[ -f ~/.claude.json ] && echo "✅ ~/.claude.json (contains MCP config)" || echo "❌ ~/.claude.json"
echo -e "\n=== PROJECT CONFIG ==="
for f in ./CLAUDE.md ./.claude/CLAUDE.md ./.claude/settings.json ./.claude/settings.local.json; do
@ -141,18 +143,41 @@ else
echo "❌ No hooks directory"
fi
# MCP servers
# MCP servers (check all locations)
echo -e "\n=== MCP SERVERS ==="
if [ -f ~/.claude/mcp.json ]; then
if command -v jq &> /dev/null; then
jq -r ".mcpServers | keys[]" ~/.claude/mcp.json 2>/dev/null
else
grep -oE "\"[a-zA-Z0-9_-]+\"\\s*:" ~/.claude/mcp.json | sed "s/\"//g;s/://g"
CURRENT_DIR=$(pwd)
# Check 1: Project-specific MCP in ~/.claude.json (most common)
if [ -f ~/.claude.json ] && command -v jq &> /dev/null; then
MCP=$(jq -r --arg path "$CURRENT_DIR" ".projects[\$path].mcpServers // {} | keys[]" ~/.claude.json 2>/dev/null)
if [ -n "$MCP" ]; then
echo "Source: ~/.claude.json (project)"
echo "$MCP"
fi
else
echo "❌ No mcp.json"
fi
# Check 2: Project-level .claude/mcp.json
if [ -z "$MCP" ] && [ -f ./.claude/mcp.json ]; then
echo "Source: .claude/mcp.json"
if command -v jq &> /dev/null; then
jq -r ".mcpServers // {} | keys[]" ./.claude/mcp.json 2>/dev/null
else
grep -oE "\"[a-zA-Z0-9_-]+\"[[:space:]]*:" ./.claude/mcp.json | sed "s/\"//g;s/://g"
fi
fi
# Check 3: Legacy global ~/.claude/mcp.json
if [ -z "$MCP" ] && [ -f ~/.claude/mcp.json ]; then
echo "Source: ~/.claude/mcp.json (global)"
if command -v jq &> /dev/null; then
jq -r ".mcpServers // {} | keys[]" ~/.claude/mcp.json 2>/dev/null
else
grep -oE "\"[a-zA-Z0-9_-]+\"[[:space:]]*:" ~/.claude/mcp.json | sed "s/\"//g;s/://g"
fi
fi
[ -z "$MCP" ] && echo "❌ No MCP servers configured for this project"
# CLAUDE.md quality
echo -e "\n=== MEMORY FILE QUALITY ==="
if [ -f ./CLAUDE.md ]; then
@ -448,7 +473,7 @@ Here's an example of what the audit report looks like:
| **Memory Files** | CLAUDE.md files that provide persistent context to Claude across sessions |
| **Single Source of Truth** | Pattern where conventions are documented once and referenced everywhere |
| **Tool SEO** | Writing agent/command descriptions so Claude selects the right tool automatically |
| **MCP Servers** | Model Context Protocol - external tools that extend Claude's capabilities |
| **MCP Servers** | Model Context Protocol - external tools that extend Claude's capabilities. Config stored in `~/.claude.json` per project, or `.claude/mcp.json` at project level |
| **Serena** | MCP server for codebase indexation and session memory persistence |
| **Context7** | MCP server for official library documentation lookup |
| **Hooks** | Scripts that run automatically on Claude events (PreToolUse, PostToolUse, etc.) |
@ -528,4 +553,4 @@ Here's an example of what the audit report looks like:
---
*Last updated: January 2026 | Version 2.8 - Optimized with bash scanning*
*Last updated: January 2026 | Version 2.9 - Fixed MCP detection (now checks ~/.claude.json)*

View file

@ -68,7 +68,13 @@ get_file_lines() {
}
count_pattern() {
[[ -f "$1" ]] && grep -c "$2" "$1" 2>/dev/null || echo "0"
if [[ -f "$1" ]]; then
local count
count=$(grep -c "$2" "$1" 2>/dev/null) || count="0"
echo "$count"
else
echo "0"
fi
}
# Expand home directory
@ -114,18 +120,62 @@ if [[ -d "./.claude/hooks" ]]; then
grep -l "PreToolUse" ./.claude/hooks/* 2>/dev/null >/dev/null && HAS_SECURITY_HOOKS="true"
fi
# MCP servers (check global config)
# MCP servers detection
# Claude Code stores MCP config in multiple locations:
# 1. ~/.claude.json under projects.<cwd>.mcpServers (per-project, most common)
# 2. ~/.claude/mcp.json (legacy global)
# 3. ./.claude/mcp.json (project-level)
MCP_SERVERS=""
if [[ -f "${GLOBAL_DIR}/mcp.json" ]]; then
# Extract server names (works with or without jq)
MCP_SOURCE=""
CURRENT_DIR=$(pwd)
# Check 1: Project-specific MCP in ~/.claude.json
if [[ -f "${HOME}/.claude.json" ]]; then
if command -v jq &> /dev/null; then
MCP_SERVERS=$(jq -r '.mcpServers | keys[]' "${GLOBAL_DIR}/mcp.json" 2>/dev/null | tr '\n' ',' | sed 's/,$//')
else
# Fallback: simple grep
MCP_SERVERS=$(grep -oE '"[a-zA-Z0-9_-]+"\\s*:' "${GLOBAL_DIR}/mcp.json" 2>/dev/null | sed 's/"//g;s/://g' | tr '\n' ',' | sed 's/,$//')
# Get MCP servers for current project path
MCP_SERVERS=$(jq -r --arg path "$CURRENT_DIR" '.projects[$path].mcpServers // {} | keys[]' "${HOME}/.claude.json" 2>/dev/null | tr '\n' ',' | sed 's/,$//')
if [[ -n "$MCP_SERVERS" ]]; then
MCP_SOURCE="~/.claude.json (project)"
fi
fi
fi
# Check 2: Project-level .claude/mcp.json
if [[ -z "$MCP_SERVERS" && -f "./.claude/mcp.json" ]]; then
if command -v jq &> /dev/null; then
MCP_SERVERS=$(jq -r '.mcpServers // {} | keys[]' "./.claude/mcp.json" 2>/dev/null | tr '\n' ',' | sed 's/,$//')
if [[ -n "$MCP_SERVERS" ]]; then
MCP_SOURCE=".claude/mcp.json (project)"
fi
else
MCP_SERVERS=$(grep -oE '"[a-zA-Z0-9_-]+"[[:space:]]*:' "./.claude/mcp.json" 2>/dev/null | head -20 | sed 's/"//g;s/://g' | tr '\n' ',' | sed 's/,$//')
if [[ -n "$MCP_SERVERS" ]]; then
MCP_SOURCE=".claude/mcp.json (project)"
fi
fi
fi
# Check 3: Legacy global ~/.claude/mcp.json
if [[ -z "$MCP_SERVERS" && -f "${GLOBAL_DIR}/mcp.json" ]]; then
if command -v jq &> /dev/null; then
MCP_SERVERS=$(jq -r '.mcpServers // {} | keys[]' "${GLOBAL_DIR}/mcp.json" 2>/dev/null | tr '\n' ',' | sed 's/,$//')
if [[ -n "$MCP_SERVERS" ]]; then
MCP_SOURCE="~/.claude/mcp.json (global)"
fi
else
MCP_SERVERS=$(grep -oE '"[a-zA-Z0-9_-]+"[[:space:]]*:' "${GLOBAL_DIR}/mcp.json" 2>/dev/null | head -20 | sed 's/"//g;s/://g' | tr '\n' ',' | sed 's/,$//')
if [[ -n "$MCP_SERVERS" ]]; then
MCP_SOURCE="~/.claude/mcp.json (global)"
fi
fi
fi
# Count MCP servers
MCP_COUNT=0
if [[ -n "$MCP_SERVERS" ]]; then
MCP_COUNT=$(echo "$MCP_SERVERS" | tr ',' '\n' | grep -c . || echo "0")
fi
# Memory file quality (if exists)
CLAUDE_MD_LINES="0"
CLAUDE_MD_REFS="0"
@ -143,13 +193,13 @@ fi
# === OUTPUT ===
if [[ "$OUTPUT_MODE" == "json" ]]; then
# JSON output
# JSON output - ensure all values are properly formatted
cat <<EOF
{
"global": {
"claude_md": $GLOBAL_CLAUDE_MD,
"settings": $GLOBAL_SETTINGS,
"mcp": $GLOBAL_MCP
"mcp_json": $GLOBAL_MCP
},
"project": {
"claude_md": $PROJECT_CLAUDE_MD,
@ -169,8 +219,13 @@ if [[ "$OUTPUT_MODE" == "json" ]]; then
"has_security_hooks": $HAS_SECURITY_HOOKS,
"has_ssot_references": $HAS_SSOT,
"claude_md_lines": $CLAUDE_MD_LINES,
"claude_md_refs": $CLAUDE_MD_REFS,
"mcp_servers": "$MCP_SERVERS"
"claude_md_refs": $CLAUDE_MD_REFS
},
"mcp": {
"configured": $([ -n "$MCP_SERVERS" ] && echo "true" || echo "false"),
"count": $MCP_COUNT,
"servers": "$MCP_SERVERS",
"source": "$MCP_SOURCE"
}
}
EOF
@ -181,7 +236,7 @@ else
echo -e "${BLUE}📁 GLOBAL CONFIG${NC} (~/.claude/)"
[[ "$GLOBAL_CLAUDE_MD" == "true" ]] && echo -e " ${GREEN}${NC} CLAUDE.md" || echo -e " ${RED}${NC} CLAUDE.md"
[[ "$GLOBAL_SETTINGS" == "true" ]] && echo -e " ${GREEN}${NC} settings.json" || echo -e " ${RED}${NC} settings.json"
[[ "$GLOBAL_MCP" == "true" ]] && echo -e " ${GREEN}${NC} mcp.json" || echo -e " ${RED}${NC} mcp.json"
[[ "$GLOBAL_MCP" == "true" ]] && echo -e " ${GREEN}${NC} mcp.json (legacy)" || echo -e " ${YELLOW}⚠️${NC} mcp.json (not required, MCP in ~/.claude.json)"
echo -e "\n${BLUE}📁 PROJECT CONFIG${NC} (./)"
[[ "$PROJECT_CLAUDE_MD" == "true" ]] && echo -e " ${GREEN}${NC} CLAUDE.md" || echo -e " ${YELLOW}⚠️${NC} CLAUDE.md (recommended)"
@ -210,9 +265,10 @@ else
fi
if [[ -n "$MCP_SERVERS" ]]; then
echo -e " ${GREEN}${NC} MCP servers: $MCP_SERVERS"
echo -e " ${GREEN}${NC} MCP servers ($MCP_COUNT): $MCP_SERVERS"
echo -e " ${BLUE}Source:${NC} $MCP_SOURCE"
else
echo -e " ${YELLOW}⚠️${NC} No MCP servers configured"
echo -e " ${YELLOW}⚠️${NC} No MCP servers configured for this project"
fi
echo -e "\n${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"