@tomsmart-ai/mcp-audit-claude-code 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # @tomsmart-ai/mcp-audit-claude-code
2
+
3
+ > MCP server for auditing Claude Code configurations. Originally built for [AI Orchestration Audit-as-a-Service](https://smartflowproai.com/work-with-me) deliverables. Open-source under MIT.
4
+
5
+ Drop this server into your own Claude Code setup and it gains three tools for self-auditing your `~/.claude/settings.json` + skills + hooks directories.
6
+
7
+ ## What it audits
8
+
9
+ ### audit_config_file
10
+
11
+ Parses your Claude Code `settings.json` and flags:
12
+ - **HIGH**: `bypassPermissions` defaultMode (security risk), hardcoded API keys leaked in config
13
+ - **MED**: missing permissions block, empty allow lists
14
+ - **LOW**: missing hooks block, no env vars set, excessive plugins enabled
15
+
16
+ ### audit_skills_dir
17
+
18
+ Scans `~/.claude/skills/` and flags per-skill:
19
+ - **MED**: missing SKILL.md, missing YAML frontmatter, missing description field
20
+ - **LOW**: description shorter than 20 chars, body shorter than 100 chars
21
+
22
+ ### audit_hooks_dir
23
+
24
+ Scans `~/.claude/hooks/` shell scripts and flags:
25
+ - **HIGH**: hook not executable (`chmod +x` missing), leaked API keys in hook content
26
+ - **MED**: missing `set -e` error handling in bash hooks
27
+ - **LOW**: hardcoded `/Users/<name>/` paths (portability hit)
28
+
29
+ ## Install
30
+
31
+ ```bash
32
+ npm install -g @tomsmart-ai/mcp-audit-claude-code
33
+ ```
34
+
35
+ ## Use with Claude Code
36
+
37
+ Add to `~/.claude.json`:
38
+
39
+ ```json
40
+ {
41
+ "mcpServers": {
42
+ "audit-claude-code": {
43
+ "command": "mcp-audit-claude-code"
44
+ }
45
+ }
46
+ }
47
+ ```
48
+
49
+ Restart Claude Code. Then ask:
50
+
51
+ ```
52
+ Audit my Claude Code config at ~/.claude/settings.json
53
+ ```
54
+
55
+ Claude calls `audit_config_file`, returns findings list with severity + fix hints.
56
+
57
+ ## Use case: AAA self-audit
58
+
59
+ This server powers the AI Orchestration Audit-as-a-Service stack audits (Tier 1 $500 — Tier 3 $1,500). When you commission an audit, this MCP server runs against your stack first, then a human review applies cultural context and shipping pragmatism on top.
60
+
61
+ If you want to skip the audit-as-a-service and run the same checks yourself, install this server and ask Claude to audit. The tools are the same; what you don't get is the cultural review layer + the implementation effort (audit-as-a-service includes one fix on Tier 2+).
62
+
63
+ ## Why open-source
64
+
65
+ The audit logic itself is straightforward — read JSON, check patterns, return findings. Selling closed access to the tool would protect zero moat. The moat is the cultural-context review + the experience auditing many stacks + knowing which findings actually matter for which workflows.
66
+
67
+ Open-source the tool, sell the judgment.
68
+
69
+ ## Roadmap
70
+
71
+ - v0.1.0 (today, Wt 26.05.2026) — initial audit tools for config, skills, hooks
72
+ - v0.2.0 — add `audit_memory_dir` for `~/.claude/projects/*/memory/` quality scan
73
+ - v0.3.0 — add `audit_mcp_server_config` for inspecting MCP server registrations
74
+ - v0.4.0 — add `recommend_hooks` returning suggested hook scaffolds for missing categories
75
+ - v0.5.0 — cross-check `audit_config_file` against `audit_hooks_dir` (consistency: hooks referenced in config exist on disk)
76
+
77
+ ## License
78
+
79
+ MIT
80
+
81
+ ## Author
82
+
83
+ Tom Smart — [smartflowproai.com](https://smartflowproai.com) · [@TomSmart_ai](https://x.com/TomSmart_ai) · [github.com/smartflowproai-lang](https://github.com/smartflowproai-lang)
84
+
85
+ Pair-built with Claude (Anthropic's coding agent). Tom scoped the tools, drafted findings categories, decided severity thresholds. Claude wrote the TypeScript. Tom reviewed each change and ran smoke tests before publish.
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * mcp-audit-claude-code v0.1.0
4
+ *
5
+ * MCP server exposing audit tools for Claude Code configurations.
6
+ * Primary use: AI Orchestration Audit-as-a-Service (AAA) deliverables.
7
+ * Secondary use: solo self-audit by anyone running Claude Code.
8
+ *
9
+ * Tools:
10
+ * - audit_config_file(file_path) — parses ~/.claude/settings.json, flags anti-patterns
11
+ * - audit_skills_dir(dir_path) — scans skill SKILL.md files for quality issues
12
+ * - audit_hooks_dir(dir_path) — checks hook scripts for safety + error handling
13
+ *
14
+ * Built Wt 26.05.2026 ~18:20 PL ja-side autonomous as Tom Smart's AAA primary new monetization project.
15
+ */
16
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,368 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * mcp-audit-claude-code v0.1.0
4
+ *
5
+ * MCP server exposing audit tools for Claude Code configurations.
6
+ * Primary use: AI Orchestration Audit-as-a-Service (AAA) deliverables.
7
+ * Secondary use: solo self-audit by anyone running Claude Code.
8
+ *
9
+ * Tools:
10
+ * - audit_config_file(file_path) — parses ~/.claude/settings.json, flags anti-patterns
11
+ * - audit_skills_dir(dir_path) — scans skill SKILL.md files for quality issues
12
+ * - audit_hooks_dir(dir_path) — checks hook scripts for safety + error handling
13
+ *
14
+ * Built Wt 26.05.2026 ~18:20 PL ja-side autonomous as Tom Smart's AAA primary new monetization project.
15
+ */
16
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
17
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
18
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
19
+ import * as fs from "node:fs";
20
+ import * as path from "node:path";
21
+ const server = new Server({
22
+ name: "@tomsmart-ai/mcp-audit-claude-code",
23
+ version: "0.1.0",
24
+ }, {
25
+ capabilities: {
26
+ tools: {},
27
+ },
28
+ });
29
+ function auditConfigFile(filePath) {
30
+ const findings = [];
31
+ if (!fs.existsSync(filePath)) {
32
+ return {
33
+ findings: [{ severity: "HIGH", category: "missing", message: `Config file not found at ${filePath}`, fix_hint: "Verify path; if Claude Code is installed, default location is ~/.claude/settings.json" }],
34
+ summary: "FAIL — config file not found",
35
+ };
36
+ }
37
+ let config;
38
+ try {
39
+ config = JSON.parse(fs.readFileSync(filePath, "utf-8"));
40
+ }
41
+ catch (e) {
42
+ return {
43
+ findings: [{ severity: "HIGH", category: "syntax", message: `JSON parse error: ${e.message}`, fix_hint: "Validate JSON syntax via `jq . settings.json`" }],
44
+ summary: "FAIL — syntax error",
45
+ };
46
+ }
47
+ // Check 1: permissions section structure
48
+ if (!config.permissions) {
49
+ findings.push({
50
+ severity: "MED",
51
+ category: "permissions",
52
+ message: "No permissions block. Claude Code will prompt on every tool call.",
53
+ fix_hint: "Add permissions section z allowlist of safe paths (Write/Edit) and tools (Bash command patterns).",
54
+ });
55
+ }
56
+ else if (config.permissions.defaultMode === "bypassPermissions") {
57
+ findings.push({
58
+ severity: "HIGH",
59
+ category: "security",
60
+ message: "defaultMode set to 'bypassPermissions' — Claude can execute arbitrary tools without confirmation.",
61
+ fix_hint: "Use 'acceptEdits' for most use cases. Reserve 'bypassPermissions' only for trusted automation contexts (CI, VPS overnight chains).",
62
+ });
63
+ }
64
+ // Check 2: hooks
65
+ if (!config.hooks || Object.keys(config.hooks).length === 0) {
66
+ findings.push({
67
+ severity: "LOW",
68
+ category: "hooks",
69
+ message: "No hooks configured. Missing opportunity for pre-prompt context injection / pre-tool-use safety / stop-hook gates.",
70
+ fix_hint: "Common hooks worth setting: UserPromptSubmit (memory grep / context injection), PreToolUse (audit / safety), PostToolUse (logging).",
71
+ });
72
+ }
73
+ // Check 3: env vars
74
+ if (!config.env) {
75
+ findings.push({
76
+ severity: "LOW",
77
+ category: "env",
78
+ message: "No env vars configured.",
79
+ fix_hint: "Consider setting CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING or other harness-level controls.",
80
+ });
81
+ }
82
+ // Check 4: hardcoded API keys
83
+ const configString = JSON.stringify(config);
84
+ const apiKeyPatterns = [
85
+ /sk_live_[a-zA-Z0-9_]{20,}/g,
86
+ /sk-ant-[a-zA-Z0-9_-]{20,}/g,
87
+ /sk-[a-zA-Z0-9_-]{20,}/g,
88
+ /AIza[a-zA-Z0-9_-]{30,}/g,
89
+ /ghp_[a-zA-Z0-9]{30,}/g,
90
+ ];
91
+ for (const pat of apiKeyPatterns) {
92
+ const m = configString.match(pat);
93
+ if (m) {
94
+ findings.push({
95
+ severity: "HIGH",
96
+ category: "secret_leak",
97
+ message: `Possible API key / token found in config: ${m[0].substring(0, 12)}…`,
98
+ fix_hint: "Move secrets to env vars OR external secret store (1Password CLI, age-encrypted file). Never commit raw secrets to settings.json.",
99
+ });
100
+ }
101
+ }
102
+ // Check 5: empty allow list
103
+ if (config.permissions?.allow && config.permissions.allow.length === 0) {
104
+ findings.push({
105
+ severity: "MED",
106
+ category: "permissions",
107
+ message: "permissions.allow is empty — every tool call will prompt.",
108
+ fix_hint: "Populate allow list z safe paths (e.g. Write(/path/to/safe-dir/**)) and Bash command patterns (e.g. Bash(ls *)).",
109
+ });
110
+ }
111
+ // Check 6: plugins enabled
112
+ if (config.enabledPlugins) {
113
+ const pluginCount = Object.keys(config.enabledPlugins).filter(k => config.enabledPlugins[k]).length;
114
+ if (pluginCount > 5) {
115
+ findings.push({
116
+ severity: "LOW",
117
+ category: "plugins",
118
+ message: `${pluginCount} plugins enabled. Each adds token overhead at startup.`,
119
+ fix_hint: "Disable unused plugins. Set value to false in enabledPlugins to keep config but skip load.",
120
+ });
121
+ }
122
+ }
123
+ const highCount = findings.filter(f => f.severity === "HIGH").length;
124
+ const medCount = findings.filter(f => f.severity === "MED").length;
125
+ const lowCount = findings.filter(f => f.severity === "LOW").length;
126
+ let summary;
127
+ if (highCount > 0)
128
+ summary = `BLOCK — ${highCount} HIGH, ${medCount} MED, ${lowCount} LOW`;
129
+ else if (medCount > 0)
130
+ summary = `WARN — ${medCount} MED, ${lowCount} LOW`;
131
+ else if (lowCount > 0)
132
+ summary = `POLISH — ${lowCount} LOW`;
133
+ else
134
+ summary = `PASS — no anti-patterns detected`;
135
+ return { findings, summary };
136
+ }
137
+ // =====================================================================
138
+ // Tool: audit_skills_dir
139
+ // =====================================================================
140
+ function auditSkillsDir(dirPath) {
141
+ const findings = [];
142
+ if (!fs.existsSync(dirPath)) {
143
+ return {
144
+ findings: [{ severity: "HIGH", category: "missing", message: `Skills directory not found at ${dirPath}`, fix_hint: "Default Claude Code skills location is ~/.claude/skills/" }],
145
+ summary: "FAIL — skills dir not found",
146
+ skill_count: 0,
147
+ };
148
+ }
149
+ const skills = fs.readdirSync(dirPath).filter(name => {
150
+ const fullPath = path.join(dirPath, name);
151
+ return fs.statSync(fullPath).isDirectory();
152
+ });
153
+ if (skills.length === 0) {
154
+ findings.push({
155
+ severity: "LOW",
156
+ category: "empty",
157
+ message: "No skills installed.",
158
+ fix_hint: "Skills provide reusable workflows. Consider building skills for common multi-step tasks.",
159
+ });
160
+ return { findings, summary: "EMPTY — no skills", skill_count: 0 };
161
+ }
162
+ for (const skillName of skills) {
163
+ const skillDir = path.join(dirPath, skillName);
164
+ const skillMdPath = path.join(skillDir, "SKILL.md");
165
+ if (!fs.existsSync(skillMdPath)) {
166
+ findings.push({
167
+ severity: "MED",
168
+ category: "skill_structure",
169
+ message: `Skill '${skillName}' missing SKILL.md`,
170
+ fix_hint: "Every skill needs SKILL.md with frontmatter (name + description) and body instructions.",
171
+ });
172
+ continue;
173
+ }
174
+ const skillMd = fs.readFileSync(skillMdPath, "utf-8");
175
+ // Check frontmatter present
176
+ if (!skillMd.startsWith("---")) {
177
+ findings.push({
178
+ severity: "MED",
179
+ category: "skill_frontmatter",
180
+ message: `Skill '${skillName}' SKILL.md missing YAML frontmatter`,
181
+ fix_hint: "Add ---\\nname: skill-name\\ndescription: When to use\\n--- at top of SKILL.md",
182
+ });
183
+ }
184
+ // Check description quality
185
+ const descMatch = skillMd.match(/description:\s*(.+)/);
186
+ if (!descMatch) {
187
+ findings.push({
188
+ severity: "MED",
189
+ category: "skill_description",
190
+ message: `Skill '${skillName}' missing description field`,
191
+ fix_hint: "description field is what Claude uses to decide if skill matches user request. Be specific about when to invoke.",
192
+ });
193
+ }
194
+ else if (descMatch[1].trim().length < 20) {
195
+ findings.push({
196
+ severity: "LOW",
197
+ category: "skill_description",
198
+ message: `Skill '${skillName}' description is short (${descMatch[1].trim().length} chars)`,
199
+ fix_hint: "Aim for 50-150 chars in description. Include trigger keywords + use cases.",
200
+ });
201
+ }
202
+ // Check body length
203
+ const bodyAfterFrontmatter = skillMd.replace(/^---[\s\S]*?---\n/, "").trim();
204
+ if (bodyAfterFrontmatter.length < 100) {
205
+ findings.push({
206
+ severity: "MED",
207
+ category: "skill_body",
208
+ message: `Skill '${skillName}' body very short (${bodyAfterFrontmatter.length} chars)`,
209
+ fix_hint: "Skill body should provide step-by-step instructions Claude follows. Short skills often miss edge cases.",
210
+ });
211
+ }
212
+ }
213
+ const summary = findings.length === 0
214
+ ? `PASS — ${skills.length} skills, no anti-patterns`
215
+ : `${findings.filter(f => f.severity === "HIGH").length} HIGH / ${findings.filter(f => f.severity === "MED").length} MED / ${findings.filter(f => f.severity === "LOW").length} LOW across ${skills.length} skills`;
216
+ return { findings, summary, skill_count: skills.length };
217
+ }
218
+ // =====================================================================
219
+ // Tool: audit_hooks_dir
220
+ // =====================================================================
221
+ function auditHooksDir(dirPath) {
222
+ const findings = [];
223
+ if (!fs.existsSync(dirPath)) {
224
+ return {
225
+ findings: [{ severity: "LOW", category: "missing", message: `Hooks directory not found at ${dirPath}`, fix_hint: "Default Claude Code hooks location is ~/.claude/hooks/" }],
226
+ summary: "EMPTY — no hooks dir",
227
+ hook_count: 0,
228
+ };
229
+ }
230
+ const hookFiles = fs.readdirSync(dirPath).filter(name => name.endsWith(".sh") || name.endsWith(".py") || name.endsWith(".js"));
231
+ if (hookFiles.length === 0) {
232
+ return { findings: [{ severity: "LOW", category: "empty", message: "No hook scripts found.", fix_hint: "Consider hooks for UserPromptSubmit (context injection), PreToolUse (audit), PostToolUse (logging)." }], summary: "EMPTY — no hooks", hook_count: 0 };
233
+ }
234
+ for (const hookFile of hookFiles) {
235
+ const fullPath = path.join(dirPath, hookFile);
236
+ const content = fs.readFileSync(fullPath, "utf-8");
237
+ const stats = fs.statSync(fullPath);
238
+ // Check executable bit (owner OR group OR world executable)
239
+ if (!(stats.mode & 0o111)) {
240
+ findings.push({
241
+ severity: "HIGH",
242
+ category: "permissions",
243
+ message: `Hook '${hookFile}' is not executable. Claude Code will NOT invoke it.`,
244
+ fix_hint: `Run: chmod +x ${fullPath}`,
245
+ });
246
+ }
247
+ // Check error handling for bash hooks
248
+ if (hookFile.endsWith(".sh")) {
249
+ if (!content.includes("set -e") && !content.includes("set -euo")) {
250
+ findings.push({
251
+ severity: "MED",
252
+ category: "error_handling",
253
+ message: `Hook '${hookFile}' missing 'set -e' or 'set -euo pipefail'`,
254
+ fix_hint: "Add 'set -euo pipefail' at top of bash hook to fail-fast on errors instead of silent corruption.",
255
+ });
256
+ }
257
+ }
258
+ // Check for hardcoded paths to current user
259
+ const userMatches = content.match(/\/Users\/[a-zA-Z0-9_-]+/g);
260
+ if (userMatches) {
261
+ findings.push({
262
+ severity: "LOW",
263
+ category: "portability",
264
+ message: `Hook '${hookFile}' has hardcoded user path (e.g. ${userMatches[0]})`,
265
+ fix_hint: "Use $HOME or ~/ instead of /Users/<name>/ for portability across machines.",
266
+ });
267
+ }
268
+ // Check for credentials in hook
269
+ const apiKeyPatterns = [/sk_live_[a-zA-Z0-9_]{20,}/, /sk-[a-zA-Z0-9_-]{20,}/];
270
+ for (const pat of apiKeyPatterns) {
271
+ if (content.match(pat)) {
272
+ findings.push({
273
+ severity: "HIGH",
274
+ category: "secret_leak",
275
+ message: `Hook '${hookFile}' contains hardcoded API key.`,
276
+ fix_hint: "Move secrets to env vars OR external secret store. Read via $VAR_NAME at hook runtime.",
277
+ });
278
+ }
279
+ }
280
+ }
281
+ const summary = findings.length === 0
282
+ ? `PASS — ${hookFiles.length} hooks, no anti-patterns`
283
+ : `${findings.filter(f => f.severity === "HIGH").length} HIGH / ${findings.filter(f => f.severity === "MED").length} MED / ${findings.filter(f => f.severity === "LOW").length} LOW across ${hookFiles.length} hooks`;
284
+ return { findings, summary, hook_count: hookFiles.length };
285
+ }
286
+ // =====================================================================
287
+ // MCP server wiring
288
+ // =====================================================================
289
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
290
+ tools: [
291
+ {
292
+ name: "audit_config_file",
293
+ description: "Audit a Claude Code settings.json configuration file for anti-patterns: missing permissions, bypassPermissions risk, hardcoded API keys, empty allow lists, excessive plugins. Returns findings with severity HIGH/MED/LOW and fix hints.",
294
+ inputSchema: {
295
+ type: "object",
296
+ properties: {
297
+ file_path: {
298
+ type: "string",
299
+ description: "Absolute path to Claude Code settings.json (typical: ~/.claude/settings.json)",
300
+ },
301
+ },
302
+ required: ["file_path"],
303
+ },
304
+ },
305
+ {
306
+ name: "audit_skills_dir",
307
+ description: "Audit a Claude Code skills directory for quality issues: missing SKILL.md, missing frontmatter, short descriptions, sparse body content. Returns findings + skill count.",
308
+ inputSchema: {
309
+ type: "object",
310
+ properties: {
311
+ dir_path: {
312
+ type: "string",
313
+ description: "Absolute path to Claude Code skills directory (typical: ~/.claude/skills/)",
314
+ },
315
+ },
316
+ required: ["dir_path"],
317
+ },
318
+ },
319
+ {
320
+ name: "audit_hooks_dir",
321
+ description: "Audit a Claude Code hooks directory: missing executable bit, missing 'set -e' error handling, hardcoded user paths, leaked credentials in hook scripts. Returns findings + hook count.",
322
+ inputSchema: {
323
+ type: "object",
324
+ properties: {
325
+ dir_path: {
326
+ type: "string",
327
+ description: "Absolute path to Claude Code hooks directory (typical: ~/.claude/hooks/)",
328
+ },
329
+ },
330
+ required: ["dir_path"],
331
+ },
332
+ },
333
+ ],
334
+ }));
335
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
336
+ const { name, arguments: args } = request.params;
337
+ let result;
338
+ if (name === "audit_config_file") {
339
+ result = auditConfigFile(args.file_path);
340
+ }
341
+ else if (name === "audit_skills_dir") {
342
+ result = auditSkillsDir(args.dir_path);
343
+ }
344
+ else if (name === "audit_hooks_dir") {
345
+ result = auditHooksDir(args.dir_path);
346
+ }
347
+ else {
348
+ throw new Error(`Unknown tool: ${name}`);
349
+ }
350
+ return {
351
+ content: [
352
+ {
353
+ type: "text",
354
+ text: JSON.stringify(result, null, 2),
355
+ },
356
+ ],
357
+ };
358
+ });
359
+ async function main() {
360
+ const transport = new StdioServerTransport();
361
+ await server.connect(transport);
362
+ console.error("mcp-audit-claude-code v0.1.0 listening on stdio");
363
+ }
364
+ main().catch((err) => {
365
+ console.error("Fatal error:", err);
366
+ process.exit(1);
367
+ });
368
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@tomsmart-ai/mcp-audit-claude-code",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for auditing Claude Code configurations (~/.claude.json + skills + hooks). Used internally for AI Orchestration Audit-as-a-Service deliverables, also usable standalone for self-audit.",
5
+ "main": "dist/index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "mcp-audit-claude-code": "dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "start": "node dist/index.js",
13
+ "dev": "tsx src/index.ts",
14
+ "test": "node test/smoke.js"
15
+ },
16
+ "keywords": [
17
+ "mcp",
18
+ "claude-code",
19
+ "audit",
20
+ "ai-orchestration",
21
+ "smartflow"
22
+ ],
23
+ "author": "Tom Smart <info@smartflowproai.com>",
24
+ "license": "MIT",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/smartflowproai-lang/mcp-audit-claude-code"
28
+ },
29
+ "homepage": "https://smartflowproai.com/work-with-me",
30
+ "dependencies": {
31
+ "@modelcontextprotocol/sdk": "^1.0.0"
32
+ },
33
+ "devDependencies": {
34
+ "typescript": "^5.3.0",
35
+ "tsx": "^4.0.0",
36
+ "@types/node": "^20.0.0"
37
+ },
38
+ "engines": {
39
+ "node": ">=18.0.0"
40
+ }
41
+ }
package/src/index.ts ADDED
@@ -0,0 +1,420 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * mcp-audit-claude-code v0.1.0
4
+ *
5
+ * MCP server exposing audit tools for Claude Code configurations.
6
+ * Primary use: AI Orchestration Audit-as-a-Service (AAA) deliverables.
7
+ * Secondary use: solo self-audit by anyone running Claude Code.
8
+ *
9
+ * Tools:
10
+ * - audit_config_file(file_path) — parses ~/.claude/settings.json, flags anti-patterns
11
+ * - audit_skills_dir(dir_path) — scans skill SKILL.md files for quality issues
12
+ * - audit_hooks_dir(dir_path) — checks hook scripts for safety + error handling
13
+ *
14
+ * Built Wt 26.05.2026 ~18:20 PL ja-side autonomous as Tom Smart's AAA primary new monetization project.
15
+ */
16
+
17
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
18
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
19
+ import {
20
+ CallToolRequestSchema,
21
+ ListToolsRequestSchema,
22
+ } from "@modelcontextprotocol/sdk/types.js";
23
+ import * as fs from "node:fs";
24
+ import * as path from "node:path";
25
+
26
+ const server = new Server(
27
+ {
28
+ name: "@tomsmart-ai/mcp-audit-claude-code",
29
+ version: "0.1.0",
30
+ },
31
+ {
32
+ capabilities: {
33
+ tools: {},
34
+ },
35
+ }
36
+ );
37
+
38
+ // =====================================================================
39
+ // Tool: audit_config_file
40
+ // =====================================================================
41
+
42
+ interface ConfigFinding {
43
+ severity: "HIGH" | "MED" | "LOW";
44
+ category: string;
45
+ message: string;
46
+ fix_hint: string;
47
+ }
48
+
49
+ function auditConfigFile(filePath: string): { findings: ConfigFinding[]; summary: string } {
50
+ const findings: ConfigFinding[] = [];
51
+
52
+ if (!fs.existsSync(filePath)) {
53
+ return {
54
+ findings: [{ severity: "HIGH", category: "missing", message: `Config file not found at ${filePath}`, fix_hint: "Verify path; if Claude Code is installed, default location is ~/.claude/settings.json" }],
55
+ summary: "FAIL — config file not found",
56
+ };
57
+ }
58
+
59
+ let config: any;
60
+ try {
61
+ config = JSON.parse(fs.readFileSync(filePath, "utf-8"));
62
+ } catch (e) {
63
+ return {
64
+ findings: [{ severity: "HIGH", category: "syntax", message: `JSON parse error: ${(e as Error).message}`, fix_hint: "Validate JSON syntax via `jq . settings.json`" }],
65
+ summary: "FAIL — syntax error",
66
+ };
67
+ }
68
+
69
+ // Check 1: permissions section structure
70
+ if (!config.permissions) {
71
+ findings.push({
72
+ severity: "MED",
73
+ category: "permissions",
74
+ message: "No permissions block. Claude Code will prompt on every tool call.",
75
+ fix_hint: "Add permissions section z allowlist of safe paths (Write/Edit) and tools (Bash command patterns).",
76
+ });
77
+ } else if (config.permissions.defaultMode === "bypassPermissions") {
78
+ findings.push({
79
+ severity: "HIGH",
80
+ category: "security",
81
+ message: "defaultMode set to 'bypassPermissions' — Claude can execute arbitrary tools without confirmation.",
82
+ fix_hint: "Use 'acceptEdits' for most use cases. Reserve 'bypassPermissions' only for trusted automation contexts (CI, VPS overnight chains).",
83
+ });
84
+ }
85
+
86
+ // Check 2: hooks
87
+ if (!config.hooks || Object.keys(config.hooks).length === 0) {
88
+ findings.push({
89
+ severity: "LOW",
90
+ category: "hooks",
91
+ message: "No hooks configured. Missing opportunity for pre-prompt context injection / pre-tool-use safety / stop-hook gates.",
92
+ fix_hint: "Common hooks worth setting: UserPromptSubmit (memory grep / context injection), PreToolUse (audit / safety), PostToolUse (logging).",
93
+ });
94
+ }
95
+
96
+ // Check 3: env vars
97
+ if (!config.env) {
98
+ findings.push({
99
+ severity: "LOW",
100
+ category: "env",
101
+ message: "No env vars configured.",
102
+ fix_hint: "Consider setting CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING or other harness-level controls.",
103
+ });
104
+ }
105
+
106
+ // Check 4: hardcoded API keys
107
+ const configString = JSON.stringify(config);
108
+ const apiKeyPatterns = [
109
+ /sk_live_[a-zA-Z0-9_]{20,}/g,
110
+ /sk-ant-[a-zA-Z0-9_-]{20,}/g,
111
+ /sk-[a-zA-Z0-9_-]{20,}/g,
112
+ /AIza[a-zA-Z0-9_-]{30,}/g,
113
+ /ghp_[a-zA-Z0-9]{30,}/g,
114
+ ];
115
+ for (const pat of apiKeyPatterns) {
116
+ const m = configString.match(pat);
117
+ if (m) {
118
+ findings.push({
119
+ severity: "HIGH",
120
+ category: "secret_leak",
121
+ message: `Possible API key / token found in config: ${m[0].substring(0, 12)}…`,
122
+ fix_hint: "Move secrets to env vars OR external secret store (1Password CLI, age-encrypted file). Never commit raw secrets to settings.json.",
123
+ });
124
+ }
125
+ }
126
+
127
+ // Check 5: empty allow list
128
+ if (config.permissions?.allow && config.permissions.allow.length === 0) {
129
+ findings.push({
130
+ severity: "MED",
131
+ category: "permissions",
132
+ message: "permissions.allow is empty — every tool call will prompt.",
133
+ fix_hint: "Populate allow list z safe paths (e.g. Write(/path/to/safe-dir/**)) and Bash command patterns (e.g. Bash(ls *)).",
134
+ });
135
+ }
136
+
137
+ // Check 6: plugins enabled
138
+ if (config.enabledPlugins) {
139
+ const pluginCount = Object.keys(config.enabledPlugins).filter(k => config.enabledPlugins[k]).length;
140
+ if (pluginCount > 5) {
141
+ findings.push({
142
+ severity: "LOW",
143
+ category: "plugins",
144
+ message: `${pluginCount} plugins enabled. Each adds token overhead at startup.`,
145
+ fix_hint: "Disable unused plugins. Set value to false in enabledPlugins to keep config but skip load.",
146
+ });
147
+ }
148
+ }
149
+
150
+ const highCount = findings.filter(f => f.severity === "HIGH").length;
151
+ const medCount = findings.filter(f => f.severity === "MED").length;
152
+ const lowCount = findings.filter(f => f.severity === "LOW").length;
153
+
154
+ let summary: string;
155
+ if (highCount > 0) summary = `BLOCK — ${highCount} HIGH, ${medCount} MED, ${lowCount} LOW`;
156
+ else if (medCount > 0) summary = `WARN — ${medCount} MED, ${lowCount} LOW`;
157
+ else if (lowCount > 0) summary = `POLISH — ${lowCount} LOW`;
158
+ else summary = `PASS — no anti-patterns detected`;
159
+
160
+ return { findings, summary };
161
+ }
162
+
163
+ // =====================================================================
164
+ // Tool: audit_skills_dir
165
+ // =====================================================================
166
+
167
+ function auditSkillsDir(dirPath: string): { findings: ConfigFinding[]; summary: string; skill_count: number } {
168
+ const findings: ConfigFinding[] = [];
169
+
170
+ if (!fs.existsSync(dirPath)) {
171
+ return {
172
+ findings: [{ severity: "HIGH", category: "missing", message: `Skills directory not found at ${dirPath}`, fix_hint: "Default Claude Code skills location is ~/.claude/skills/" }],
173
+ summary: "FAIL — skills dir not found",
174
+ skill_count: 0,
175
+ };
176
+ }
177
+
178
+ const skills = fs.readdirSync(dirPath).filter(name => {
179
+ const fullPath = path.join(dirPath, name);
180
+ return fs.statSync(fullPath).isDirectory();
181
+ });
182
+
183
+ if (skills.length === 0) {
184
+ findings.push({
185
+ severity: "LOW",
186
+ category: "empty",
187
+ message: "No skills installed.",
188
+ fix_hint: "Skills provide reusable workflows. Consider building skills for common multi-step tasks.",
189
+ });
190
+ return { findings, summary: "EMPTY — no skills", skill_count: 0 };
191
+ }
192
+
193
+ for (const skillName of skills) {
194
+ const skillDir = path.join(dirPath, skillName);
195
+ const skillMdPath = path.join(skillDir, "SKILL.md");
196
+
197
+ if (!fs.existsSync(skillMdPath)) {
198
+ findings.push({
199
+ severity: "MED",
200
+ category: "skill_structure",
201
+ message: `Skill '${skillName}' missing SKILL.md`,
202
+ fix_hint: "Every skill needs SKILL.md with frontmatter (name + description) and body instructions.",
203
+ });
204
+ continue;
205
+ }
206
+
207
+ const skillMd = fs.readFileSync(skillMdPath, "utf-8");
208
+
209
+ // Check frontmatter present
210
+ if (!skillMd.startsWith("---")) {
211
+ findings.push({
212
+ severity: "MED",
213
+ category: "skill_frontmatter",
214
+ message: `Skill '${skillName}' SKILL.md missing YAML frontmatter`,
215
+ fix_hint: "Add ---\\nname: skill-name\\ndescription: When to use\\n--- at top of SKILL.md",
216
+ });
217
+ }
218
+
219
+ // Check description quality
220
+ const descMatch = skillMd.match(/description:\s*(.+)/);
221
+ if (!descMatch) {
222
+ findings.push({
223
+ severity: "MED",
224
+ category: "skill_description",
225
+ message: `Skill '${skillName}' missing description field`,
226
+ fix_hint: "description field is what Claude uses to decide if skill matches user request. Be specific about when to invoke.",
227
+ });
228
+ } else if (descMatch[1].trim().length < 20) {
229
+ findings.push({
230
+ severity: "LOW",
231
+ category: "skill_description",
232
+ message: `Skill '${skillName}' description is short (${descMatch[1].trim().length} chars)`,
233
+ fix_hint: "Aim for 50-150 chars in description. Include trigger keywords + use cases.",
234
+ });
235
+ }
236
+
237
+ // Check body length
238
+ const bodyAfterFrontmatter = skillMd.replace(/^---[\s\S]*?---\n/, "").trim();
239
+ if (bodyAfterFrontmatter.length < 100) {
240
+ findings.push({
241
+ severity: "MED",
242
+ category: "skill_body",
243
+ message: `Skill '${skillName}' body very short (${bodyAfterFrontmatter.length} chars)`,
244
+ fix_hint: "Skill body should provide step-by-step instructions Claude follows. Short skills often miss edge cases.",
245
+ });
246
+ }
247
+ }
248
+
249
+ const summary = findings.length === 0
250
+ ? `PASS — ${skills.length} skills, no anti-patterns`
251
+ : `${findings.filter(f => f.severity === "HIGH").length} HIGH / ${findings.filter(f => f.severity === "MED").length} MED / ${findings.filter(f => f.severity === "LOW").length} LOW across ${skills.length} skills`;
252
+
253
+ return { findings, summary, skill_count: skills.length };
254
+ }
255
+
256
+ // =====================================================================
257
+ // Tool: audit_hooks_dir
258
+ // =====================================================================
259
+
260
+ function auditHooksDir(dirPath: string): { findings: ConfigFinding[]; summary: string; hook_count: number } {
261
+ const findings: ConfigFinding[] = [];
262
+
263
+ if (!fs.existsSync(dirPath)) {
264
+ return {
265
+ findings: [{ severity: "LOW", category: "missing", message: `Hooks directory not found at ${dirPath}`, fix_hint: "Default Claude Code hooks location is ~/.claude/hooks/" }],
266
+ summary: "EMPTY — no hooks dir",
267
+ hook_count: 0,
268
+ };
269
+ }
270
+
271
+ const hookFiles = fs.readdirSync(dirPath).filter(name => name.endsWith(".sh") || name.endsWith(".py") || name.endsWith(".js"));
272
+
273
+ if (hookFiles.length === 0) {
274
+ return { findings: [{ severity: "LOW", category: "empty", message: "No hook scripts found.", fix_hint: "Consider hooks for UserPromptSubmit (context injection), PreToolUse (audit), PostToolUse (logging)." }], summary: "EMPTY — no hooks", hook_count: 0 };
275
+ }
276
+
277
+ for (const hookFile of hookFiles) {
278
+ const fullPath = path.join(dirPath, hookFile);
279
+ const content = fs.readFileSync(fullPath, "utf-8");
280
+ const stats = fs.statSync(fullPath);
281
+
282
+ // Check executable bit (owner OR group OR world executable)
283
+ if (!(stats.mode & 0o111)) {
284
+ findings.push({
285
+ severity: "HIGH",
286
+ category: "permissions",
287
+ message: `Hook '${hookFile}' is not executable. Claude Code will NOT invoke it.`,
288
+ fix_hint: `Run: chmod +x ${fullPath}`,
289
+ });
290
+ }
291
+
292
+ // Check error handling for bash hooks
293
+ if (hookFile.endsWith(".sh")) {
294
+ if (!content.includes("set -e") && !content.includes("set -euo")) {
295
+ findings.push({
296
+ severity: "MED",
297
+ category: "error_handling",
298
+ message: `Hook '${hookFile}' missing 'set -e' or 'set -euo pipefail'`,
299
+ fix_hint: "Add 'set -euo pipefail' at top of bash hook to fail-fast on errors instead of silent corruption.",
300
+ });
301
+ }
302
+ }
303
+
304
+ // Check for hardcoded paths to current user
305
+ const userMatches = content.match(/\/Users\/[a-zA-Z0-9_-]+/g);
306
+ if (userMatches) {
307
+ findings.push({
308
+ severity: "LOW",
309
+ category: "portability",
310
+ message: `Hook '${hookFile}' has hardcoded user path (e.g. ${userMatches[0]})`,
311
+ fix_hint: "Use $HOME or ~/ instead of /Users/<name>/ for portability across machines.",
312
+ });
313
+ }
314
+
315
+ // Check for credentials in hook
316
+ const apiKeyPatterns = [/sk_live_[a-zA-Z0-9_]{20,}/, /sk-[a-zA-Z0-9_-]{20,}/];
317
+ for (const pat of apiKeyPatterns) {
318
+ if (content.match(pat)) {
319
+ findings.push({
320
+ severity: "HIGH",
321
+ category: "secret_leak",
322
+ message: `Hook '${hookFile}' contains hardcoded API key.`,
323
+ fix_hint: "Move secrets to env vars OR external secret store. Read via $VAR_NAME at hook runtime.",
324
+ });
325
+ }
326
+ }
327
+ }
328
+
329
+ const summary = findings.length === 0
330
+ ? `PASS — ${hookFiles.length} hooks, no anti-patterns`
331
+ : `${findings.filter(f => f.severity === "HIGH").length} HIGH / ${findings.filter(f => f.severity === "MED").length} MED / ${findings.filter(f => f.severity === "LOW").length} LOW across ${hookFiles.length} hooks`;
332
+
333
+ return { findings, summary, hook_count: hookFiles.length };
334
+ }
335
+
336
+ // =====================================================================
337
+ // MCP server wiring
338
+ // =====================================================================
339
+
340
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
341
+ tools: [
342
+ {
343
+ name: "audit_config_file",
344
+ description: "Audit a Claude Code settings.json configuration file for anti-patterns: missing permissions, bypassPermissions risk, hardcoded API keys, empty allow lists, excessive plugins. Returns findings with severity HIGH/MED/LOW and fix hints.",
345
+ inputSchema: {
346
+ type: "object",
347
+ properties: {
348
+ file_path: {
349
+ type: "string",
350
+ description: "Absolute path to Claude Code settings.json (typical: ~/.claude/settings.json)",
351
+ },
352
+ },
353
+ required: ["file_path"],
354
+ },
355
+ },
356
+ {
357
+ name: "audit_skills_dir",
358
+ description: "Audit a Claude Code skills directory for quality issues: missing SKILL.md, missing frontmatter, short descriptions, sparse body content. Returns findings + skill count.",
359
+ inputSchema: {
360
+ type: "object",
361
+ properties: {
362
+ dir_path: {
363
+ type: "string",
364
+ description: "Absolute path to Claude Code skills directory (typical: ~/.claude/skills/)",
365
+ },
366
+ },
367
+ required: ["dir_path"],
368
+ },
369
+ },
370
+ {
371
+ name: "audit_hooks_dir",
372
+ description: "Audit a Claude Code hooks directory: missing executable bit, missing 'set -e' error handling, hardcoded user paths, leaked credentials in hook scripts. Returns findings + hook count.",
373
+ inputSchema: {
374
+ type: "object",
375
+ properties: {
376
+ dir_path: {
377
+ type: "string",
378
+ description: "Absolute path to Claude Code hooks directory (typical: ~/.claude/hooks/)",
379
+ },
380
+ },
381
+ required: ["dir_path"],
382
+ },
383
+ },
384
+ ],
385
+ }));
386
+
387
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
388
+ const { name, arguments: args } = request.params;
389
+
390
+ let result: any;
391
+ if (name === "audit_config_file") {
392
+ result = auditConfigFile(args!.file_path as string);
393
+ } else if (name === "audit_skills_dir") {
394
+ result = auditSkillsDir(args!.dir_path as string);
395
+ } else if (name === "audit_hooks_dir") {
396
+ result = auditHooksDir(args!.dir_path as string);
397
+ } else {
398
+ throw new Error(`Unknown tool: ${name}`);
399
+ }
400
+
401
+ return {
402
+ content: [
403
+ {
404
+ type: "text",
405
+ text: JSON.stringify(result, null, 2),
406
+ },
407
+ ],
408
+ };
409
+ });
410
+
411
+ async function main() {
412
+ const transport = new StdioServerTransport();
413
+ await server.connect(transport);
414
+ console.error("mcp-audit-claude-code v0.1.0 listening on stdio");
415
+ }
416
+
417
+ main().catch((err) => {
418
+ console.error("Fatal error:", err);
419
+ process.exit(1);
420
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ES2020",
5
+ "moduleResolution": "node",
6
+ "outDir": "./dist",
7
+ "rootDir": "./src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "declaration": true,
13
+ "sourceMap": true
14
+ },
15
+ "include": ["src/**/*"],
16
+ "exclude": ["node_modules", "dist"]
17
+ }