@cognium-ai/mcp-server 0.2.1 → 0.4.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 CHANGED
@@ -1,9 +1,22 @@
1
1
  # @cognium-ai/mcp-server
2
2
 
3
- An [MCP](https://modelcontextprotocol.io) server exposing Cognium's
4
- spec-conformance, spec-drift, and pattern-search tools over **stdio**. Backed
5
- by the [`circle-ir-ai`](https://www.npmjs.com/package/circle-ir-ai) engine's
6
- `analyzeSpecGap`.
3
+ An [MCP](https://modelcontextprotocol.io) server exposing Cognium's security
4
+ scanning and spec-conformance tools over **stdio**. Backed by the
5
+ [`circle-ir-ai`](https://www.npmjs.com/package/circle-ir-ai) engine.
6
+
7
+ ## Tools Overview
8
+
9
+ | Tool | Category | Description |
10
+ |------|----------|-------------|
11
+ | `find_credential_exposure` | Pillar I | Detect hardcoded secrets (AWS, GitHub, OpenAI, etc.) |
12
+ | `check_license_compliance` | Pillar I | Flag copyleft licenses in dependencies |
13
+ | `find_stale_dependencies` | Pillar I | Check npm registry for outdated packages |
14
+ | `find_install_script_risk` | Pillar I | Detect malicious install script patterns |
15
+ | `find_typosquats` | Pillar I | Detect typosquat package names |
16
+ | `find_excessive_permissions` | Pillar I | Audit MCP config permissions |
17
+ | `verify_spec_conformance` | Spec | Analyze code-to-spec alignment |
18
+ | `find_spec_drift` | Spec | Report spec/code drift |
19
+ | `find_pattern` | Utility | Regex search over code |
7
20
 
8
21
  ## Install & run
9
22
 
@@ -31,7 +44,111 @@ Inspect it interactively:
31
44
  npx @modelcontextprotocol/inspector cognium-mcp
32
45
  ```
33
46
 
34
- ## Tools
47
+ ## Pillar I Security Tools
48
+
49
+ All Pillar I tools return a common envelope:
50
+
51
+ ```jsonc
52
+ {
53
+ "findings": [{ "kind": "...", "severity": "...", "location": {...}, "evidence": {...}, "suggested_action": "..." }],
54
+ "summary": { "total": N, "by_severity": {...}, "truncated": false }
55
+ }
56
+ ```
57
+
58
+ - `location.span` is **1-indexed line numbers** `[start_line, end_line]`
59
+ - All tools accept `severity_floor` to filter results
60
+
61
+ ### `find_credential_exposure`
62
+
63
+ Detect hardcoded secrets using SAST pattern matching.
64
+
65
+ | Input | Type | Description |
66
+ |-------|------|-------------|
67
+ | `code_root` | string | Absolute path to scan |
68
+ | `include_git_history` | boolean | Scan git history (default: false) |
69
+ | `severity_floor` | enum | Minimum severity: info/low/medium/high/critical |
70
+
71
+ **Evidence:** `rule_id`, `match_snippet` (redacted), `confidence`
72
+
73
+ ### `check_license_compliance`
74
+
75
+ Flag copyleft licenses in npm/Cargo dependencies.
76
+
77
+ | Input | Type | Description |
78
+ |-------|------|-------------|
79
+ | `code_root` | string | Absolute path to scan |
80
+ | `include_dev_deps` | boolean | Include devDependencies (default: false) |
81
+ | `severity_floor` | enum | Minimum severity |
82
+
83
+ **Severity:** AGPL/SSPL=critical, GPL=high, LGPL/MPL=medium, EUPL/CPAL=low
84
+
85
+ ### `find_stale_dependencies`
86
+
87
+ Check npm dependencies for staleness and known vulnerabilities.
88
+
89
+ | Input | Type | Description |
90
+ |-------|------|-------------|
91
+ | `code_root` | string | Absolute path to scan |
92
+ | `include_dev_deps` | boolean | Include devDependencies (default: false) |
93
+ | `severity_floor` | enum | Minimum severity |
94
+ | `check_vulnerabilities` | boolean | Query OSV for CVEs (default: true) |
95
+
96
+ **Staleness severity:** >3 years=high, >2 years=medium, >1 year=low
97
+
98
+ **Vulnerability severity:** CVSS ≥9.0=critical, ≥7.0=high, ≥4.0=medium, <4.0=low
99
+
100
+ **Evidence:**
101
+ - Staleness: `dependency`, `current_version`, `latest_version`, `days_since_publish`, `last_publish_date`
102
+ - Vulnerability: `dependency`, `current_version`, `vuln_id`, `cve`, `cvss`, `summary`
103
+
104
+ ### `find_install_script_risk`
105
+
106
+ Detect malicious patterns in npm lifecycle scripts (preinstall, postinstall, etc.).
107
+
108
+ | Input | Type | Description |
109
+ |-------|------|-------------|
110
+ | `code_root` | string | Absolute path to scan |
111
+ | `severity_floor` | enum | Minimum severity |
112
+
113
+ **Rules:** piped downloads (critical), eval/exec (critical), base64 decode (high), env exfiltration (high), network downloads (medium), hidden file writes (medium)
114
+
115
+ ### `find_typosquats`
116
+
117
+ Detect typosquat package names using Levenshtein distance and homoglyph detection.
118
+
119
+ | Input | Type | Description |
120
+ |-------|------|-------------|
121
+ | `code_root` | string | Absolute path to scan |
122
+ | `include_dev_deps` | boolean | Include devDependencies (default: false) |
123
+ | `severity_floor` | enum | Minimum severity |
124
+ | `check_homoglyphs` | boolean | Detect visual deception attacks (default: true) |
125
+ | `check_popularity` | boolean | Query npm for download counts (default: false) |
126
+
127
+ **Detection methods:**
128
+ - **Levenshtein:** distance=1 is high, distance=2 is medium
129
+ - **Homoglyph:** detects visual deception (`rn`→`m`, `1`→`l`, `0`→`o`, etc.) - always high severity
130
+
131
+ **Evidence:** `dependency`, `similar_to`, `detection_method`, `distance`, `homoglyph`, `target_downloads`
132
+
133
+ ### `find_excessive_permissions`
134
+
135
+ Audit MCP server configurations for overly broad permissions.
136
+
137
+ | Input | Type | Description |
138
+ |-------|------|-------------|
139
+ | `code_root` | string | Absolute path to scan |
140
+ | `severity_floor` | enum | Minimum severity |
141
+ | `deep_analysis` | boolean | Run CircleIR to detect undisclosed capabilities (default: true) |
142
+
143
+ **Config formats:** skill bundle (mcp.json), Claude Desktop, Cursor
144
+
145
+ **Static rules:** broad filesystem paths, secret env vars, unrestricted network, dangerous commands
146
+
147
+ **Deep analysis:** Cross-references declared permissions against actual code behavior. Detects undisclosed network, filesystem, or process execution capabilities.
148
+
149
+ ---
150
+
151
+ ## Spec Tools
35
152
 
36
153
  ### `verify_spec_conformance`
37
154
 
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOpE,wBAAgB,WAAW,IAAI,SAAS,CAavC"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAWpE,wBAAgB,WAAW,IAAI,SAAS,CAsBvC"}
package/dist/server.js CHANGED
@@ -7,16 +7,27 @@ import { registerFindSpecDrift } from './tools/find-spec-drift.js';
7
7
  import { registerFindPattern } from './tools/find-pattern.js';
8
8
  import { registerFindCredentialExposure } from './tools/find-credential-exposure.js';
9
9
  import { registerCheckLicenseCompliance } from './tools/check-license-compliance.js';
10
+ import { registerFindStaleDependencies } from './tools/find-stale-dependencies.js';
11
+ import { registerFindInstallScriptRisk } from './tools/find-install-script-risk.js';
12
+ import { registerFindTyposquats } from './tools/find-typosquats.js';
13
+ import { registerFindExcessivePermissions } from './tools/find-excessive-permissions.js';
10
14
  export function buildServer() {
11
15
  const server = new McpServer({
12
16
  name: 'cognium-mcp',
13
- version: '0.2.1',
17
+ version: '0.4.0',
14
18
  });
19
+ // Spec tools (legacy)
15
20
  registerVerifySpecConformance(server);
16
21
  registerFindSpecDrift(server);
17
22
  registerFindPattern(server);
23
+ // Pillar I Batch 1
18
24
  registerFindCredentialExposure(server);
19
25
  registerCheckLicenseCompliance(server);
26
+ // Pillar I Batch 2
27
+ registerFindStaleDependencies(server);
28
+ registerFindInstallScriptRisk(server);
29
+ registerFindTyposquats(server);
30
+ registerFindExcessivePermissions(server);
20
31
  return server;
21
32
  }
22
33
  //# sourceMappingURL=server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,6BAA6B,EAAE,MAAM,oCAAoC,CAAC;AACnF,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AACrF,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AAErF,MAAM,UAAU,WAAW;IACzB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,6BAA6B,CAAC,MAAM,CAAC,CAAC;IACtC,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC9B,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC5B,8BAA8B,CAAC,MAAM,CAAC,CAAC;IACvC,8BAA8B,CAAC,MAAM,CAAC,CAAC;IAEvC,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,6BAA6B,EAAE,MAAM,oCAAoC,CAAC;AACnF,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AACrF,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AACrF,OAAO,EAAE,6BAA6B,EAAE,MAAM,oCAAoC,CAAC;AACnF,OAAO,EAAE,6BAA6B,EAAE,MAAM,qCAAqC,CAAC;AACpF,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,gCAAgC,EAAE,MAAM,uCAAuC,CAAC;AAEzF,MAAM,UAAU,WAAW;IACzB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,sBAAsB;IACtB,6BAA6B,CAAC,MAAM,CAAC,CAAC;IACtC,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC9B,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAE5B,mBAAmB;IACnB,8BAA8B,CAAC,MAAM,CAAC,CAAC;IACvC,8BAA8B,CAAC,MAAM,CAAC,CAAC;IAEvC,mBAAmB;IACnB,6BAA6B,CAAC,MAAM,CAAC,CAAC;IACtC,6BAA6B,CAAC,MAAM,CAAC,CAAC;IACtC,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,gCAAgC,CAAC,MAAM,CAAC,CAAC;IAEzC,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * find_excessive_permissions MCP tool (Pillar I, Batch 2).
3
+ *
4
+ * Analyzes MCP server configurations for overly broad or dangerous permissions.
5
+ * Supports: skill bundle (mcp.json), Claude Desktop, Cursor configs.
6
+ *
7
+ * Auto-detection heuristic:
8
+ * - Files named mcp.json, .mcp.json, mcp-config.json → skill bundle format
9
+ * - claude_desktop_config.json → Claude Desktop format
10
+ * - .cursor/mcp.json → Cursor format
11
+ *
12
+ * @see https://github.com/cogniumhq/cognium-ai/issues/80
13
+ */
14
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
15
+ export declare function registerFindExcessivePermissions(server: McpServer): void;
16
+ //# sourceMappingURL=find-excessive-permissions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-excessive-permissions.d.ts","sourceRoot":"","sources":["../../src/tools/find-excessive-permissions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAiGzE,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAmExE"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * find_excessive_permissions MCP tool (Pillar I, Batch 2).
3
+ *
4
+ * Analyzes MCP server configurations for overly broad or dangerous permissions.
5
+ * Supports: skill bundle (mcp.json), Claude Desktop, Cursor configs.
6
+ *
7
+ * Auto-detection heuristic:
8
+ * - Files named mcp.json, .mcp.json, mcp-config.json → skill bundle format
9
+ * - claude_desktop_config.json → Claude Desktop format
10
+ * - .cursor/mcp.json → Cursor format
11
+ *
12
+ * @see https://github.com/cogniumhq/cognium-ai/issues/80
13
+ */
14
+ import { z } from 'zod';
15
+ import { excessivePermissionsPass } from 'circle-ir-ai';
16
+ import { loadCircleIR } from '../analysis.js';
17
+ const MAX_FINDINGS = 500;
18
+ const SEVERITY_ORDER = {
19
+ info: 0,
20
+ low: 1,
21
+ medium: 2,
22
+ high: 3,
23
+ critical: 4,
24
+ };
25
+ const inputSchema = {
26
+ code_root: z.string().describe('Absolute path to the code root to scan'),
27
+ severity_floor: z.enum(['info', 'low', 'medium', 'high', 'critical']).optional().default('low').describe('Minimum severity to report (default: low)'),
28
+ deep_analysis: z.boolean().optional().default(true).describe('Run CircleIR analysis to detect undisclosed capabilities (default: true)'),
29
+ };
30
+ const outputSchema = {
31
+ findings: z.array(z.object({
32
+ kind: z.literal('EXCESSIVE_PERMISSION'),
33
+ severity: z.enum(['low', 'medium', 'high', 'critical']),
34
+ location: z.object({
35
+ file: z.string(),
36
+ span: z.tuple([z.number(), z.number()]),
37
+ }),
38
+ evidence: z.object({
39
+ rule_id: z.string(),
40
+ config_file: z.string(),
41
+ permission_type: z.string(),
42
+ value: z.string(),
43
+ }),
44
+ suggested_action: z.string(),
45
+ })),
46
+ summary: z.object({
47
+ total: z.number(),
48
+ by_severity: z.object({
49
+ critical: z.number(),
50
+ high: z.number(),
51
+ medium: z.number(),
52
+ low: z.number(),
53
+ }),
54
+ truncated: z.boolean(),
55
+ }),
56
+ detection_info: z.object({
57
+ config_files_checked: z.array(z.string()),
58
+ auto_detection_heuristic: z.string(),
59
+ deep_analysis_performed: z.boolean(),
60
+ files_analyzed: z.number().optional(),
61
+ }),
62
+ };
63
+ const SUGGESTED_ACTIONS = {
64
+ 'perm-broad-filesystem': 'Restrict filesystem access to specific directories needed by the tool. Avoid /home, /Users, or ~ wildcards.',
65
+ 'perm-secret-env-exposure': 'Remove sensitive environment variables from MCP config. Use secrets management instead.',
66
+ 'perm-unrestricted-network': 'Restrict network access to specific hosts/ports needed by the tool.',
67
+ 'perm-dangerous-command': 'Review and restrict allowed commands. Avoid shell interpreters and system utilities.',
68
+ 'perm-write-sensitive-path': 'Restrict write access to user-specific directories. Avoid system paths.',
69
+ };
70
+ function trustFindingToMcp(f) {
71
+ const meta = f.meta;
72
+ return {
73
+ kind: 'EXCESSIVE_PERMISSION',
74
+ severity: f.severity === 'info' ? 'low' : f.severity,
75
+ location: {
76
+ file: f.location?.file ?? 'mcp.json',
77
+ span: [f.location?.line ?? 1, f.location?.line ?? 1],
78
+ },
79
+ evidence: {
80
+ rule_id: f.ruleId,
81
+ config_file: f.location?.file ?? 'mcp.json',
82
+ permission_type: meta.permissionType ?? 'unknown',
83
+ value: meta.value ?? '',
84
+ },
85
+ suggested_action: SUGGESTED_ACTIONS[f.ruleId] ?? 'Review this permission for security risks and apply least-privilege principle.',
86
+ };
87
+ }
88
+ export function registerFindExcessivePermissions(server) {
89
+ server.registerTool('find_excessive_permissions', {
90
+ title: 'Find Excessive Permissions',
91
+ description: 'Analyze MCP server configurations for overly broad permissions. ' +
92
+ 'Detects: broad filesystem paths (/home, /Users, ~), secret env var exposure, ' +
93
+ 'unrestricted network access, dangerous command allowlisting. ' +
94
+ 'Auto-detects config format (skill bundle, Claude Desktop, Cursor).',
95
+ inputSchema,
96
+ outputSchema,
97
+ }, async ({ code_root, severity_floor, deep_analysis }) => {
98
+ // Run CircleIR analysis for deep capability detection
99
+ let circleIRResults;
100
+ if (deep_analysis !== false) {
101
+ try {
102
+ const { results } = await loadCircleIR(code_root);
103
+ circleIRResults = results;
104
+ }
105
+ catch {
106
+ // CircleIR analysis failed, continue with static-only analysis
107
+ }
108
+ }
109
+ const result = await excessivePermissionsPass(code_root, { circleIRResults });
110
+ const floorValue = SEVERITY_ORDER[severity_floor ?? 'low'];
111
+ const filtered = result.findings.filter((f) => SEVERITY_ORDER[f.severity] >= floorValue);
112
+ const truncated = filtered.length > MAX_FINDINGS;
113
+ const findings = filtered.slice(0, MAX_FINDINGS).map(trustFindingToMcp);
114
+ const output = {
115
+ findings,
116
+ summary: {
117
+ total: filtered.length,
118
+ by_severity: {
119
+ critical: filtered.filter((f) => f.severity === 'critical').length,
120
+ high: filtered.filter((f) => f.severity === 'high').length,
121
+ medium: filtered.filter((f) => f.severity === 'medium').length,
122
+ low: filtered.filter((f) => f.severity === 'low').length,
123
+ },
124
+ truncated,
125
+ },
126
+ detection_info: {
127
+ config_files_checked: [
128
+ 'mcp.json', '.mcp.json', 'mcp-config.json',
129
+ 'claude_desktop_config.json', '.cursor/mcp.json',
130
+ ],
131
+ auto_detection_heuristic: 'Files named mcp.json/.mcp.json/mcp-config.json use skill bundle format. ' +
132
+ 'claude_desktop_config.json uses Claude Desktop format. ' +
133
+ '.cursor/mcp.json uses Cursor format.',
134
+ deep_analysis_performed: !!circleIRResults,
135
+ files_analyzed: circleIRResults?.length,
136
+ },
137
+ };
138
+ return {
139
+ content: [{ type: 'text', text: JSON.stringify(output) }],
140
+ structuredContent: output,
141
+ };
142
+ });
143
+ }
144
+ //# sourceMappingURL=find-excessive-permissions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-excessive-permissions.js","sourceRoot":"","sources":["../../src/tools/find-excessive-permissions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * find_install_script_risk MCP tool (Pillar I, Batch 2).
3
+ *
4
+ * Analyzes npm package.json lifecycle scripts for suspicious patterns.
5
+ * Scope: npm lifecycle scripts only (preinstall, install, postinstall, prepare, etc.)
6
+ *
7
+ * @see https://github.com/cogniumhq/cognium-ai/issues/80
8
+ */
9
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
10
+ export declare function registerFindInstallScriptRisk(server: McpServer): void;
11
+ //# sourceMappingURL=find-install-script-risk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-install-script-risk.d.ts","sourceRoot":"","sources":["../../src/tools/find-install-script-risk.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAgGzE,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA2CrE"}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * find_install_script_risk MCP tool (Pillar I, Batch 2).
3
+ *
4
+ * Analyzes npm package.json lifecycle scripts for suspicious patterns.
5
+ * Scope: npm lifecycle scripts only (preinstall, install, postinstall, prepare, etc.)
6
+ *
7
+ * @see https://github.com/cogniumhq/cognium-ai/issues/80
8
+ */
9
+ import { z } from 'zod';
10
+ import { maliciousInstallScriptPass } from 'circle-ir-ai';
11
+ const MAX_FINDINGS = 500;
12
+ const MAX_SNIPPET_LENGTH = 200;
13
+ const SEVERITY_ORDER = {
14
+ info: 0,
15
+ low: 1,
16
+ medium: 2,
17
+ high: 3,
18
+ critical: 4,
19
+ };
20
+ const inputSchema = {
21
+ code_root: z.string().describe('Absolute path to the code root to scan'),
22
+ severity_floor: z.enum(['info', 'low', 'medium', 'high', 'critical']).optional().default('low').describe('Minimum severity to report (default: low)'),
23
+ };
24
+ const outputSchema = {
25
+ findings: z.array(z.object({
26
+ kind: z.literal('MALICIOUS_INSTALL_SCRIPT'),
27
+ severity: z.enum(['low', 'medium', 'high', 'critical']),
28
+ location: z.object({
29
+ file: z.string(),
30
+ span: z.tuple([z.number(), z.number()]),
31
+ }),
32
+ evidence: z.object({
33
+ rule_id: z.string(),
34
+ script_name: z.string(),
35
+ script_content: z.string(),
36
+ pattern_matched: z.string(),
37
+ }),
38
+ suggested_action: z.string(),
39
+ })),
40
+ summary: z.object({
41
+ total: z.number(),
42
+ by_severity: z.object({
43
+ critical: z.number(),
44
+ high: z.number(),
45
+ medium: z.number(),
46
+ low: z.number(),
47
+ }),
48
+ truncated: z.boolean(),
49
+ }),
50
+ };
51
+ const SUGGESTED_ACTIONS = {
52
+ 'install-script-piped-download': 'Remove piped download execution. If external resources are needed, download explicitly and verify checksums.',
53
+ 'install-script-eval-exec': 'Remove dynamic code execution. Use static scripts instead of eval/exec patterns.',
54
+ 'install-script-base64-decode': 'Remove base64 obfuscation. Install scripts should be readable and auditable.',
55
+ 'install-script-env-exfil': 'Remove environment variable access that could leak secrets. Document required env vars instead.',
56
+ 'install-script-network-download': 'Avoid network downloads in install scripts. Bundle dependencies or use npm dependencies.',
57
+ 'install-script-hidden-file-write': 'Avoid writing to hidden files/directories. Use explicit, documented paths.',
58
+ };
59
+ function truncate(str, max) {
60
+ if (str.length <= max)
61
+ return str;
62
+ return str.slice(0, max - 3) + '...';
63
+ }
64
+ function trustFindingToMcp(f) {
65
+ const meta = f.meta;
66
+ return {
67
+ kind: 'MALICIOUS_INSTALL_SCRIPT',
68
+ severity: f.severity === 'info' ? 'low' : f.severity,
69
+ location: {
70
+ file: f.location?.file ?? 'package.json',
71
+ span: [f.location?.line ?? 1, f.location?.line ?? 1],
72
+ },
73
+ evidence: {
74
+ rule_id: f.ruleId,
75
+ script_name: meta.scriptName ?? 'unknown',
76
+ script_content: truncate(meta.scriptContent ?? '', MAX_SNIPPET_LENGTH),
77
+ pattern_matched: f.ruleId,
78
+ },
79
+ suggested_action: SUGGESTED_ACTIONS[f.ruleId] ?? 'Review this install script for security risks.',
80
+ };
81
+ }
82
+ export function registerFindInstallScriptRisk(server) {
83
+ server.registerTool('find_install_script_risk', {
84
+ title: 'Find Install Script Risk',
85
+ description: 'Analyze npm package.json lifecycle scripts (preinstall, install, postinstall, prepare) ' +
86
+ 'for suspicious patterns: piped downloads, eval/exec, base64 decoding, env exfiltration, ' +
87
+ 'network downloads, hidden file writes. npm lifecycle scripts only.',
88
+ inputSchema,
89
+ outputSchema,
90
+ }, async ({ code_root, severity_floor }) => {
91
+ const result = await maliciousInstallScriptPass(code_root, {});
92
+ const floorValue = SEVERITY_ORDER[severity_floor ?? 'low'];
93
+ const filtered = result.findings.filter((f) => SEVERITY_ORDER[f.severity] >= floorValue);
94
+ const truncated = filtered.length > MAX_FINDINGS;
95
+ const findings = filtered.slice(0, MAX_FINDINGS).map(trustFindingToMcp);
96
+ const output = {
97
+ findings,
98
+ summary: {
99
+ total: filtered.length,
100
+ by_severity: {
101
+ critical: filtered.filter((f) => f.severity === 'critical').length,
102
+ high: filtered.filter((f) => f.severity === 'high').length,
103
+ medium: filtered.filter((f) => f.severity === 'medium').length,
104
+ low: filtered.filter((f) => f.severity === 'low').length,
105
+ },
106
+ truncated,
107
+ },
108
+ };
109
+ return {
110
+ content: [{ type: 'text', text: JSON.stringify(output) }],
111
+ structuredContent: output,
112
+ };
113
+ });
114
+ }
115
+ //# sourceMappingURL=find-install-script-risk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-install-script-risk.js","sourceRoot":"","sources":["../../src/tools/find-install-script-risk.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * find_stale_dependencies MCP tool (Pillar I, Batch 2).
3
+ *
4
+ * Checks npm dependencies for:
5
+ * 1. Staleness: last publish date via npm registry
6
+ * 2. Known vulnerabilities: via OSV (Open Source Vulnerabilities) API
7
+ *
8
+ * npm package.json only (pypi/cargo/go deferred).
9
+ *
10
+ * @see https://github.com/cogniumhq/cognium-ai/issues/80
11
+ */
12
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
13
+ export declare function registerFindStaleDependencies(server: McpServer): void;
14
+ //# sourceMappingURL=find-stale-dependencies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-stale-dependencies.d.ts","sourceRoot":"","sources":["../../src/tools/find-stale-dependencies.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAoJzE,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA+DrE"}
@@ -0,0 +1,177 @@
1
+ /**
2
+ * find_stale_dependencies MCP tool (Pillar I, Batch 2).
3
+ *
4
+ * Checks npm dependencies for:
5
+ * 1. Staleness: last publish date via npm registry
6
+ * 2. Known vulnerabilities: via OSV (Open Source Vulnerabilities) API
7
+ *
8
+ * npm package.json only (pypi/cargo/go deferred).
9
+ *
10
+ * @see https://github.com/cogniumhq/cognium-ai/issues/80
11
+ */
12
+ import { z } from 'zod';
13
+ import { dependencyStalenessPass } from 'circle-ir-ai';
14
+ const MAX_FINDINGS = 500;
15
+ const SEVERITY_ORDER = {
16
+ info: 0,
17
+ low: 1,
18
+ medium: 2,
19
+ high: 3,
20
+ critical: 4,
21
+ };
22
+ const inputSchema = {
23
+ code_root: z.string().describe('Absolute path to the code root to scan'),
24
+ include_dev_deps: z.boolean().optional().default(false).describe('Include devDependencies (default: false)'),
25
+ severity_floor: z.enum(['info', 'low', 'medium', 'high', 'critical']).optional().default('low').describe('Minimum severity to report (default: low)'),
26
+ check_vulnerabilities: z.boolean().optional().default(true).describe('Check for known vulnerabilities via OSV database (default: true)'),
27
+ };
28
+ const outputSchema = {
29
+ findings: z.array(z.object({
30
+ kind: z.enum(['STALE_DEPENDENCY', 'VULNERABLE_DEPENDENCY']),
31
+ severity: z.enum(['low', 'medium', 'high', 'critical']),
32
+ location: z.object({
33
+ file: z.string(),
34
+ span: z.tuple([z.number(), z.number()]),
35
+ }),
36
+ evidence: z.object({
37
+ rule_id: z.string(),
38
+ dependency: z.string(),
39
+ current_version: z.string(),
40
+ latest_version: z.string().nullable(),
41
+ finding_type: z.enum(['staleness', 'maintainer', 'vulnerability']),
42
+ // Staleness fields
43
+ days_since_publish: z.number().optional(),
44
+ last_publish_date: z.string().optional(),
45
+ // Vulnerability fields
46
+ vuln_id: z.string().optional(),
47
+ cve: z.string().optional(),
48
+ cvss: z.number().optional(),
49
+ summary: z.string().optional(),
50
+ }),
51
+ suggested_action: z.string(),
52
+ })),
53
+ summary: z.object({
54
+ total: z.number(),
55
+ by_severity: z.object({
56
+ critical: z.number(),
57
+ high: z.number(),
58
+ medium: z.number(),
59
+ low: z.number(),
60
+ }),
61
+ by_finding_type: z.object({
62
+ staleness: z.number(),
63
+ maintainer: z.number(),
64
+ vulnerability: z.number(),
65
+ }),
66
+ truncated: z.boolean(),
67
+ }),
68
+ };
69
+ function trustFindingToMcp(f) {
70
+ const meta = f.meta;
71
+ const findingType = meta.findingType ?? 'staleness';
72
+ const days = meta.daysSincePublish ?? 0;
73
+ let action = 'Consider updating to the latest version.';
74
+ let kind = 'STALE_DEPENDENCY';
75
+ if (findingType === 'vulnerability') {
76
+ kind = 'VULNERABLE_DEPENDENCY';
77
+ const cve = meta.cve;
78
+ const vulnId = meta.vulnId;
79
+ const cvss = meta.cvss;
80
+ if (cvss && cvss >= 9.0) {
81
+ action = `CRITICAL vulnerability ${cve ?? vulnId}. Upgrade immediately or remove this dependency.`;
82
+ }
83
+ else if (cvss && cvss >= 7.0) {
84
+ action = `HIGH severity vulnerability ${cve ?? vulnId}. Upgrade to a patched version as soon as possible.`;
85
+ }
86
+ else {
87
+ action = `Known vulnerability ${cve ?? vulnId}. Upgrade to a patched version when available.`;
88
+ }
89
+ }
90
+ else if (findingType === 'maintainer') {
91
+ action = 'This package has zero maintainers on npm. High risk of abandonment - find an alternative.';
92
+ }
93
+ else if (days > 1095) {
94
+ action = 'This package has not been updated in over 3 years. Evaluate if it is still maintained or find an alternative.';
95
+ }
96
+ else if (days > 730) {
97
+ action = 'This package has not been updated in over 2 years. Check for security advisories and consider alternatives.';
98
+ }
99
+ else if (days > 365) {
100
+ action = 'This package has not been updated in over 1 year. Monitor for updates.';
101
+ }
102
+ return {
103
+ kind,
104
+ severity: f.severity === 'info' ? 'low' : f.severity,
105
+ location: {
106
+ file: f.location?.file ?? 'package.json',
107
+ span: [f.location?.line ?? 1, f.location?.line ?? 1],
108
+ },
109
+ evidence: {
110
+ rule_id: f.ruleId,
111
+ dependency: meta.dependency ?? 'unknown',
112
+ current_version: meta.currentVersion ?? 'unknown',
113
+ latest_version: meta.latestVersion ?? null,
114
+ finding_type: findingType,
115
+ // Staleness fields (only for staleness findings)
116
+ ...(findingType === 'staleness' && {
117
+ days_since_publish: meta.daysSincePublish ?? 0,
118
+ last_publish_date: meta.lastPublishDate ?? '',
119
+ }),
120
+ // Vulnerability fields (only for vulnerability findings)
121
+ ...(findingType === 'vulnerability' && {
122
+ vuln_id: meta.vulnId,
123
+ cve: meta.cve,
124
+ cvss: meta.cvss,
125
+ summary: meta.summary,
126
+ }),
127
+ },
128
+ suggested_action: action,
129
+ };
130
+ }
131
+ export function registerFindStaleDependencies(server) {
132
+ server.registerTool('find_stale_dependencies', {
133
+ title: 'Find Stale Dependencies',
134
+ description: 'Check npm dependencies for staleness and known vulnerabilities. ' +
135
+ 'Staleness: flags packages not updated in >1 year (low), >2 years (medium), >3 years (high). ' +
136
+ 'Vulnerabilities: queries OSV database for CVEs affecting your exact versions. ' +
137
+ 'Also flags packages with zero maintainers. npm package.json only.',
138
+ inputSchema,
139
+ outputSchema,
140
+ }, async ({ code_root, include_dev_deps, severity_floor, check_vulnerabilities }) => {
141
+ const result = await dependencyStalenessPass(code_root, {
142
+ includeDevDeps: include_dev_deps,
143
+ checkVulnerabilities: check_vulnerabilities,
144
+ });
145
+ const floorValue = SEVERITY_ORDER[severity_floor ?? 'low'];
146
+ const filtered = result.findings.filter((f) => SEVERITY_ORDER[f.severity] >= floorValue);
147
+ const truncated = filtered.length > MAX_FINDINGS;
148
+ const findings = filtered.slice(0, MAX_FINDINGS).map(trustFindingToMcp);
149
+ // Count by finding type
150
+ const stalenessCount = filtered.filter((f) => f.meta?.findingType === 'staleness').length;
151
+ const maintainerCount = filtered.filter((f) => f.meta?.findingType === 'maintainer').length;
152
+ const vulnerabilityCount = filtered.filter((f) => f.meta?.findingType === 'vulnerability').length;
153
+ const output = {
154
+ findings,
155
+ summary: {
156
+ total: filtered.length,
157
+ by_severity: {
158
+ critical: filtered.filter((f) => f.severity === 'critical').length,
159
+ high: filtered.filter((f) => f.severity === 'high').length,
160
+ medium: filtered.filter((f) => f.severity === 'medium').length,
161
+ low: filtered.filter((f) => f.severity === 'low').length,
162
+ },
163
+ by_finding_type: {
164
+ staleness: stalenessCount,
165
+ maintainer: maintainerCount,
166
+ vulnerability: vulnerabilityCount,
167
+ },
168
+ truncated,
169
+ },
170
+ };
171
+ return {
172
+ content: [{ type: 'text', text: JSON.stringify(output) }],
173
+ structuredContent: output,
174
+ };
175
+ });
176
+ }
177
+ //# sourceMappingURL=find-stale-dependencies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-stale-dependencies.js","sourceRoot":"","sources":["../../src/tools/find-stale-dependencies.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * find_typosquats MCP tool (Pillar I, Batch 2).
3
+ *
4
+ * Detects potential typosquat packages by comparing dependency names
5
+ * against popular npm packages using Levenshtein distance.
6
+ *
7
+ * @see https://github.com/cogniumhq/cognium-ai/issues/80
8
+ */
9
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
10
+ export declare function registerFindTyposquats(server: McpServer): void;
11
+ //# sourceMappingURL=find-typosquats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-typosquats.d.ts","sourceRoot":"","sources":["../../src/tools/find-typosquats.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAgHzE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA2D9D"}
@@ -0,0 +1,141 @@
1
+ /**
2
+ * find_typosquats MCP tool (Pillar I, Batch 2).
3
+ *
4
+ * Detects potential typosquat packages by comparing dependency names
5
+ * against popular npm packages using Levenshtein distance.
6
+ *
7
+ * @see https://github.com/cogniumhq/cognium-ai/issues/80
8
+ */
9
+ import { z } from 'zod';
10
+ import { typosquatDetectionPass } from 'circle-ir-ai';
11
+ const MAX_FINDINGS = 500;
12
+ const SEVERITY_ORDER = {
13
+ info: 0,
14
+ low: 1,
15
+ medium: 2,
16
+ high: 3,
17
+ critical: 4,
18
+ };
19
+ const inputSchema = {
20
+ code_root: z.string().describe('Absolute path to the code root to scan'),
21
+ include_dev_deps: z.boolean().optional().default(false).describe('Include devDependencies (default: false)'),
22
+ severity_floor: z.enum(['info', 'low', 'medium', 'high', 'critical']).optional().default('low').describe('Minimum severity to report (default: low)'),
23
+ check_homoglyphs: z.boolean().optional().default(true).describe('Detect homoglyph attacks like "rn" vs "m" (default: true)'),
24
+ check_popularity: z.boolean().optional().default(false).describe('Query npm for download counts (slower, default: false)'),
25
+ };
26
+ const outputSchema = {
27
+ findings: z.array(z.object({
28
+ kind: z.literal('TYPOSQUAT_RISK'),
29
+ severity: z.enum(['medium', 'high']),
30
+ location: z.object({
31
+ file: z.string(),
32
+ span: z.tuple([z.number(), z.number()]),
33
+ }),
34
+ evidence: z.object({
35
+ rule_id: z.string(),
36
+ dependency: z.string(),
37
+ similar_to: z.string(),
38
+ detection_method: z.enum(['levenshtein', 'homoglyph']),
39
+ distance: z.number().optional(),
40
+ homoglyph: z.string().optional(),
41
+ target_downloads: z.number().optional(),
42
+ }),
43
+ suggested_action: z.string(),
44
+ })),
45
+ summary: z.object({
46
+ total: z.number(),
47
+ by_severity: z.object({
48
+ critical: z.number(),
49
+ high: z.number(),
50
+ medium: z.number(),
51
+ low: z.number(),
52
+ }),
53
+ by_detection_method: z.object({
54
+ levenshtein: z.number(),
55
+ homoglyph: z.number(),
56
+ }),
57
+ truncated: z.boolean(),
58
+ }),
59
+ };
60
+ function trustFindingToMcp(f) {
61
+ const meta = f.meta;
62
+ const dependency = meta.dependency ?? 'unknown';
63
+ const similarTo = meta.similarTo ?? 'unknown';
64
+ const detectionMethod = meta.detectionMethod ?? 'levenshtein';
65
+ const distance = meta.distance;
66
+ const homoglyph = meta.homoglyph;
67
+ const targetDownloads = meta.targetDownloads;
68
+ let action;
69
+ if (detectionMethod === 'homoglyph') {
70
+ action = `"${dependency}" uses visual deception (${homoglyph}) to mimic "${similarTo}". This is a high-confidence typosquat attack. Remove immediately.`;
71
+ }
72
+ else if (distance === 1) {
73
+ action = `"${dependency}" is 1 character away from "${similarTo}". Verify this is intentional and not a typosquat attack.`;
74
+ }
75
+ else {
76
+ action = `"${dependency}" is similar to "${similarTo}". Verify this is the intended package.`;
77
+ }
78
+ return {
79
+ kind: 'TYPOSQUAT_RISK',
80
+ severity: f.severity === 'high' ? 'high' : 'medium',
81
+ location: {
82
+ file: f.location?.file ?? 'package.json',
83
+ span: [f.location?.line ?? 1, f.location?.line ?? 1],
84
+ },
85
+ evidence: {
86
+ rule_id: f.ruleId,
87
+ dependency,
88
+ similar_to: similarTo,
89
+ detection_method: detectionMethod,
90
+ ...(distance !== undefined && { distance }),
91
+ ...(homoglyph && { homoglyph }),
92
+ ...(targetDownloads !== undefined && { target_downloads: targetDownloads }),
93
+ },
94
+ suggested_action: action,
95
+ };
96
+ }
97
+ export function registerFindTyposquats(server) {
98
+ server.registerTool('find_typosquats', {
99
+ title: 'Find Typosquats',
100
+ description: 'Detect potential typosquat packages using Levenshtein distance and homoglyph detection. ' +
101
+ 'Homoglyph attacks use visual deception (e.g., "rn" looks like "m", "1" looks like "l"). ' +
102
+ 'Protects against attacks like "lodahs" (typo) or "rnaterial-ui" (homoglyph for "material-ui").',
103
+ inputSchema,
104
+ outputSchema,
105
+ }, async ({ code_root, include_dev_deps, severity_floor, check_homoglyphs, check_popularity }) => {
106
+ const result = await typosquatDetectionPass(code_root, {
107
+ includeDevDeps: include_dev_deps,
108
+ checkHomoglyphs: check_homoglyphs,
109
+ checkPopularity: check_popularity,
110
+ });
111
+ const floorValue = SEVERITY_ORDER[severity_floor ?? 'low'];
112
+ const filtered = result.findings.filter((f) => SEVERITY_ORDER[f.severity] >= floorValue);
113
+ const truncated = filtered.length > MAX_FINDINGS;
114
+ const findings = filtered.slice(0, MAX_FINDINGS).map(trustFindingToMcp);
115
+ // Count by detection method
116
+ const levenshteinCount = filtered.filter((f) => f.meta?.detectionMethod === 'levenshtein').length;
117
+ const homoglyphCount = filtered.filter((f) => f.meta?.detectionMethod === 'homoglyph').length;
118
+ const output = {
119
+ findings,
120
+ summary: {
121
+ total: filtered.length,
122
+ by_severity: {
123
+ critical: filtered.filter((f) => f.severity === 'critical').length,
124
+ high: filtered.filter((f) => f.severity === 'high').length,
125
+ medium: filtered.filter((f) => f.severity === 'medium').length,
126
+ low: filtered.filter((f) => f.severity === 'low').length,
127
+ },
128
+ by_detection_method: {
129
+ levenshtein: levenshteinCount,
130
+ homoglyph: homoglyphCount,
131
+ },
132
+ truncated,
133
+ },
134
+ };
135
+ return {
136
+ content: [{ type: 'text', text: JSON.stringify(output) }],
137
+ structuredContent: output,
138
+ };
139
+ });
140
+ }
141
+ //# sourceMappingURL=find-typosquats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-typosquats.js","sourceRoot":"","sources":["../../src/tools/find-typosquats.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cognium-ai/mcp-server",
3
- "version": "0.2.1",
3
+ "version": "0.4.0",
4
4
  "description": "MCP server exposing Cognium spec-conformance, spec-drift, and pattern-search tools over stdio",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -46,7 +46,7 @@
46
46
  "dependencies": {
47
47
  "@modelcontextprotocol/sdk": "^1.29.0",
48
48
  "circle-ir": "^3.23.3",
49
- "circle-ir-ai": "^2.8.0",
49
+ "circle-ir-ai": "^2.8.3",
50
50
  "minimatch": "^10.2.5",
51
51
  "zod": "^3.25.0"
52
52
  },