circle-ir-ai 4.16.5 → 4.17.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.
Files changed (75) hide show
  1. package/CHANGELOG.md +52 -8
  2. package/README.md +20 -0
  3. package/dist/mcp/analysis.d.ts +25 -0
  4. package/dist/mcp/analysis.d.ts.map +1 -0
  5. package/dist/mcp/analysis.js +45 -0
  6. package/dist/mcp/analysis.js.map +1 -0
  7. package/dist/mcp/index.d.ts +24 -0
  8. package/dist/mcp/index.d.ts.map +1 -0
  9. package/dist/mcp/index.js +67 -0
  10. package/dist/mcp/index.js.map +1 -0
  11. package/dist/mcp/mappers.d.ts +41 -0
  12. package/dist/mcp/mappers.d.ts.map +1 -0
  13. package/dist/mcp/mappers.js +69 -0
  14. package/dist/mcp/mappers.js.map +1 -0
  15. package/dist/mcp/result.d.ts +32 -0
  16. package/dist/mcp/result.d.ts.map +1 -0
  17. package/dist/mcp/result.js +35 -0
  18. package/dist/mcp/result.js.map +1 -0
  19. package/dist/mcp/tools/check-license-compliance.d.ts +11 -0
  20. package/dist/mcp/tools/check-license-compliance.d.ts.map +1 -0
  21. package/dist/mcp/tools/check-license-compliance.js +124 -0
  22. package/dist/mcp/tools/check-license-compliance.js.map +1 -0
  23. package/dist/mcp/tools/find-credential-exposure.d.ts +20 -0
  24. package/dist/mcp/tools/find-credential-exposure.d.ts.map +1 -0
  25. package/dist/mcp/tools/find-credential-exposure.js +205 -0
  26. package/dist/mcp/tools/find-credential-exposure.js.map +1 -0
  27. package/dist/mcp/tools/find-excessive-permissions.d.ts +16 -0
  28. package/dist/mcp/tools/find-excessive-permissions.d.ts.map +1 -0
  29. package/dist/mcp/tools/find-excessive-permissions.js +143 -0
  30. package/dist/mcp/tools/find-excessive-permissions.js.map +1 -0
  31. package/dist/mcp/tools/find-install-script-risk.d.ts +11 -0
  32. package/dist/mcp/tools/find-install-script-risk.d.ts.map +1 -0
  33. package/dist/mcp/tools/find-install-script-risk.js +114 -0
  34. package/dist/mcp/tools/find-install-script-risk.js.map +1 -0
  35. package/dist/mcp/tools/find-pattern.d.ts +13 -0
  36. package/dist/mcp/tools/find-pattern.d.ts.map +1 -0
  37. package/dist/mcp/tools/find-pattern.js +113 -0
  38. package/dist/mcp/tools/find-pattern.js.map +1 -0
  39. package/dist/mcp/tools/find-spec-drift.d.ts +10 -0
  40. package/dist/mcp/tools/find-spec-drift.d.ts.map +1 -0
  41. package/dist/mcp/tools/find-spec-drift.js +40 -0
  42. package/dist/mcp/tools/find-spec-drift.js.map +1 -0
  43. package/dist/mcp/tools/find-stale-dependencies.d.ts +14 -0
  44. package/dist/mcp/tools/find-stale-dependencies.d.ts.map +1 -0
  45. package/dist/mcp/tools/find-stale-dependencies.js +176 -0
  46. package/dist/mcp/tools/find-stale-dependencies.js.map +1 -0
  47. package/dist/mcp/tools/find-typosquats.d.ts +11 -0
  48. package/dist/mcp/tools/find-typosquats.d.ts.map +1 -0
  49. package/dist/mcp/tools/find-typosquats.js +140 -0
  50. package/dist/mcp/tools/find-typosquats.js.map +1 -0
  51. package/dist/mcp/tools/layer-bom.d.ts +15 -0
  52. package/dist/mcp/tools/layer-bom.d.ts.map +1 -0
  53. package/dist/mcp/tools/layer-bom.js +97 -0
  54. package/dist/mcp/tools/layer-bom.js.map +1 -0
  55. package/dist/mcp/tools/verify-spec-conformance.d.ts +9 -0
  56. package/dist/mcp/tools/verify-spec-conformance.d.ts.map +1 -0
  57. package/dist/mcp/tools/verify-spec-conformance.js +46 -0
  58. package/dist/mcp/tools/verify-spec-conformance.js.map +1 -0
  59. package/dist/mcp/types.d.ts +36 -0
  60. package/dist/mcp/types.d.ts.map +1 -0
  61. package/dist/mcp/types.js +17 -0
  62. package/dist/mcp/types.js.map +1 -0
  63. package/dist/mcp/walk.d.ts +33 -0
  64. package/dist/mcp/walk.d.ts.map +1 -0
  65. package/dist/mcp/walk.js +83 -0
  66. package/dist/mcp/walk.js.map +1 -0
  67. package/dist/secret-scan/scanner.d.ts +7 -0
  68. package/dist/secret-scan/scanner.d.ts.map +1 -1
  69. package/dist/secret-scan/scanner.js +1 -1
  70. package/dist/secret-scan/scanner.js.map +1 -1
  71. package/package.json +17 -2
  72. package/dist/coverage/index.d.ts +0 -50
  73. package/dist/coverage/index.d.ts.map +0 -1
  74. package/dist/coverage/index.js +0 -73
  75. package/dist/coverage/index.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -7,6 +7,45 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Added
11
+ - **`circle-ir-ai/mcp` — this library's ten MCP tools as a module for `@cognium/mcp-server`**
12
+ (4.17.0). The server looks for this entry at startup and, when the package is installed and
13
+ built against the same `circle-ir` minor, registers the tools after its own eleven. Built
14
+ against `circle-ir` 4.9.29 and tested with `@cognium/mcp-server` 0.2.0 and MCP SDK ^1.30.1.
15
+ The tools are the ones `@cognium-ai/mcp-server` served, with the same names and arguments:
16
+ `verify_spec_conformance`, `find_spec_drift`, `find_pattern`, `find_credential_exposure`,
17
+ `check_license_compliance`, `find_stale_dependencies`, `find_install_script_risk`,
18
+ `find_typosquats`, `find_excessive_permissions`, `layer_bom`.
19
+
20
+ The server is not a dependency. `@modelcontextprotocol/sdk` is an optional peer, needed only
21
+ by a host that loads this entry; `zod` (^4) is now a direct dependency, where it was already
22
+ present transitively.
23
+
24
+ - **Every response carries `provenance`**: `deterministic`, or `llm: <model>` when a model
25
+ judged something in that call. It is in each tool's output schema, as a required field.
26
+ - **Nine of the ten tools are deterministic.** The only model path is `llm_verify` on
27
+ `find_credential_exposure`, which is off by default, marked `LLM-backed` in the tool and
28
+ argument descriptions, and runs only when the call asks for it.
29
+ - **`llm_verify` is refused on an install that is not enabled for it** — no configured
30
+ endpoint (`COGNIUM_ENDPOINT`) and no licence token. The call returns one line as an error
31
+ result. Before, the engine skipped verification and returned the unverified findings with
32
+ nothing to say so.
33
+ - **The configured endpoint is where the model is.** With an endpoint, verification goes to
34
+ it; with a licence token and no endpoint, the `LLM_*` environment applies as before.
35
+ - `SecretScanOptions.llmConfig` — overrides merged over the environment-derived LLM
36
+ configuration for the verifier, so a caller that was handed an endpoint can use it without
37
+ writing to `process.env`. Unset, behaviour is unchanged.
38
+
39
+ #### Consumer Impact
40
+ - **`find_credential_exposure` with `llm_verify: true` and no enablement now returns an error
41
+ result (`isError: true`) instead of findings.** A client that does not check `isError` and
42
+ reads `structuredContent` will find it absent. Call without `llm_verify`, or configure
43
+ `COGNIUM_ENDPOINT` or a licence token. Applies only through this module; the
44
+ `scanForSecrets` API itself is unchanged.
45
+ - **Tool input schemas are now generated by zod 4.** Names, types and required arguments are
46
+ the same; incidental JSON Schema details (`$schema`, how defaults are expressed) can differ
47
+ from what `@cognium-ai/mcp-server` published.
48
+
10
49
  ### Changed
11
50
  - **`circle-ir` 4.9.27 → 4.9.29.** All four packages re-pinned; suites pass unchanged
12
51
  (circle-ir-ai 2340, cognium-ai 363, mcp-server 11, circle-pack 182) and each resolves exactly
@@ -36,15 +75,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
36
75
  **cognium-dev#503 landed:** CWE-81 went 0.0% → 88.9% and CWE-94 0.0% → 100%, the two families
37
76
  that were at exactly zero and that ticket's two missing sinks.
38
77
 
39
- **Precision regressed sharply, and only where cognium-dev#508 applies.** CWE-89 sqli and
40
- CWE-643 xpath now fire on **100% of their files including every `Good*()` safe control** (27/27
41
- and 10/10), and CWE-94 on 90%. The other six families hold **0.0% FPR** at 88.9–90% recall.
42
- More bound sources produce proportionally more bogus source×sink pairings: CWE-89 cross-method
43
- leaks went 3 → 12 → 27 across the same three releases. #508 is now the top C# precision item,
44
- reported there with this evidence.
78
+ **cognium-dev#508 and #509 are fixed in 4.9.29.** Verified on the published build: the probes
79
+ where a tainted parameter never reaches the query (`D2_NoSibling`, `D4_TaintUnused`) are now
80
+ clean, and one SQLi emits one finding rather than two. They still reproduced on 4.9.28.
81
+
82
+ **Precision regressed sharply anyway, via a different mechanism.** CWE-89 sqli and CWE-643
83
+ xpath now fire on **100% of their files including every `Good*()` safe control** (27/27 and
84
+ 10/10), and CWE-94 on 90%, while the other six families hold **0.0% FPR** at 88.9–90% recall.
85
+ All 27 CWE-89 false-positive files are **cross-method leaks** (`xLeak` 27 of 27) — taint
86
+ associated across a `Bad()`→`Good*()` boundary by variable name, the cognium-dev#316 family,
87
+ not #508's source×sink pairing. Leaks went 3 → 12 → 27 as more sources bound, so the recall
88
+ work and that leak multiply.
45
89
 
46
- **Not fixed in either release:** cognium-dev#520 (`HtmlEncoder` still uncredited, so
47
- `xss_htmlencode_safe` remains the sole FP on both C# synthetic gates), #508, #509.
90
+ **Not fixed:** cognium-dev#520 (`HtmlEncoder` still uncredited, so `xss_htmlencode_safe`
91
+ remains the sole FP on both C# synthetic gates).
48
92
 
49
93
  **Carried-over regression:** `rmp_serde::from_slice` is still not a deserialization sink, so
50
94
  MessagePack over a `TcpStream` is undetected — Rust synthetic 97.3% TPR, down from 100%.
package/README.md CHANGED
@@ -213,9 +213,29 @@ Top findings: Jenkins (9), HuggingFace (4), Tauri (6-7), TiKV (3), Deno (3), Car
213
213
  | Bash | Shell script command-injection / code-injection detection |
214
214
  | HTML | XSS detection in templates |
215
215
 
216
+ ## MCP tools
217
+
218
+ `circle-ir-ai/mcp` exports this library's ten MCP tools as a module for
219
+ [`@cognium/mcp-server`](https://www.npmjs.com/package/@cognium/mcp-server). Install both and the
220
+ server finds the module at startup and lists the tools after its own:
221
+
222
+ ```bash
223
+ npm install @cognium/mcp-server circle-ir-ai
224
+ npx mcp-server-cognium-dev
225
+ ```
226
+
227
+ The module is refused, on one line of stderr, if it was built against a different `circle-ir`
228
+ minor than the server has; the server's own tools keep serving.
229
+
230
+ Every response carries `provenance`: `deterministic`, or `llm: <model>` when a model judged
231
+ something in that call. Nine of the ten tools are deterministic. The one model path is
232
+ `llm_verify` on `find_credential_exposure`: off by default, and refused with one line unless
233
+ the install has a configured endpoint (`COGNIUM_ENDPOINT`) or a licence token.
234
+
216
235
  ## Related Packages
217
236
 
218
237
  - **[circle-ir](https://github.com/cogniumhq/circle-ir)**: Core SAST library (open source, MIT)
238
+ - **[@cognium/mcp-server](https://www.npmjs.com/package/@cognium/mcp-server)**: The MCP server that loads `circle-ir-ai/mcp` (MIT)
219
239
 
220
240
  ## License
221
241
 
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Circle-IR loading for the MCP tools.
3
+ *
4
+ * Wraps circle-ir-ai's analyzer lifecycle: initialize the WASM-backed
5
+ * analyzer once, walk the code root for supported source files, and run
6
+ * circle-ir's `analyze` per file. The resulting `CircleIR[]` is the input to
7
+ * `analyzeSpecGap` (used by the verify/drift tools).
8
+ *
9
+ * Mirrors the wiring recipe in cognium-ai's `spec-diff` command, but depends
10
+ * only on `circle-ir` + `circle-ir-ai` (not the cognium-ai CLI).
11
+ */
12
+ import { type CircleIR } from 'circle-ir';
13
+ import { type WalkOptions } from './walk.js';
14
+ export interface LoadedCircleIR {
15
+ /** Absolute path to the analyzed code root. */
16
+ codePath: string;
17
+ /** Per-file circle-ir analysis results. */
18
+ results: CircleIR[];
19
+ }
20
+ /**
21
+ * Walk `codeRoot`, analyze each supported source file, and return the
22
+ * collected `CircleIR[]` alongside the resolved code path.
23
+ */
24
+ export declare function loadCircleIR(codeRoot: string, options?: WalkOptions): Promise<LoadedCircleIR>;
25
+ //# sourceMappingURL=analysis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analysis.d.ts","sourceRoot":"","sources":["../../src/mcp/analysis.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,EAAW,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEnD,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAEjE,MAAM,WAAW,cAAc;IAC7B,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,OAAO,EAAE,QAAQ,EAAE,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAChC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,cAAc,CAAC,CAwBzB"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Circle-IR loading for the MCP tools.
3
+ *
4
+ * Wraps circle-ir-ai's analyzer lifecycle: initialize the WASM-backed
5
+ * analyzer once, walk the code root for supported source files, and run
6
+ * circle-ir's `analyze` per file. The resulting `CircleIR[]` is the input to
7
+ * `analyzeSpecGap` (used by the verify/drift tools).
8
+ *
9
+ * Mirrors the wiring recipe in cognium-ai's `spec-diff` command, but depends
10
+ * only on `circle-ir` + `circle-ir-ai` (not the cognium-ai CLI).
11
+ */
12
+ import * as fs from 'fs';
13
+ import * as path from 'path';
14
+ import { analyze } from 'circle-ir';
15
+ import { ensureAnalyzerInitialized } from '../utils/analyzer-init.js';
16
+ import { collectSourceFiles } from './walk.js';
17
+ /**
18
+ * Walk `codeRoot`, analyze each supported source file, and return the
19
+ * collected `CircleIR[]` alongside the resolved code path.
20
+ */
21
+ export async function loadCircleIR(codeRoot, options = {}) {
22
+ await ensureAnalyzerInitialized();
23
+ const codePath = path.resolve(codeRoot);
24
+ const files = collectSourceFiles(codePath, options);
25
+ const results = [];
26
+ for (const file of files) {
27
+ let content;
28
+ try {
29
+ content = fs.readFileSync(file.absolutePath, 'utf-8');
30
+ }
31
+ catch {
32
+ continue;
33
+ }
34
+ try {
35
+ const ir = await analyze(content, path.basename(file.absolutePath), file.language);
36
+ results.push(ir);
37
+ }
38
+ catch {
39
+ // Skip files circle-ir can't parse; spec-gap tolerates a partial corpus.
40
+ continue;
41
+ }
42
+ }
43
+ return { codePath, results };
44
+ }
45
+ //# sourceMappingURL=analysis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analysis.js","sourceRoot":"","sources":["../../src/mcp/analysis.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,OAAO,EAAiB,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAoB,MAAM,WAAW,CAAC;AASjE;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,QAAgB,EAChB,UAAuB,EAAE;IAEzB,MAAM,yBAAyB,EAAE,CAAC;IAElC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxC,MAAM,KAAK,GAAG,kBAAkB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAEpD,MAAM,OAAO,GAAe,EAAE,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,OAAe,CAAC;QACpB,IAAI,CAAC;YACH,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACxD,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;YACnF,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnB,CAAC;QAAC,MAAM,CAAC;YACP,yEAAyE;YACzE,SAAS;QACX,CAAC;IACH,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * `circle-ir-ai/mcp` — this library's tools as a module for the one MCP
3
+ * server.
4
+ *
5
+ * `@cognium/mcp-server` looks for this entry when it starts and, if the
6
+ * package is installed and built against the same `circle-ir` minor,
7
+ * registers these tools after its own. The server is not a dependency of
8
+ * this package and is never bundled with it: the module only describes
9
+ * itself and registers handlers over this library's own functions.
10
+ *
11
+ * Nine of the ten tools are deterministic. `find_credential_exposure` is
12
+ * deterministic unless it is called with `llm_verify`, which asks a model to
13
+ * re-check the candidates; that path runs only when asked for by name, only
14
+ * on an install that is enabled for it, and refuses otherwise.
15
+ */
16
+ import type { CircleIrAiToolModule } from './types.js';
17
+ /** The tools this module registers, in registration order. */
18
+ export declare const TOOL_NAMES: readonly ["verify_spec_conformance", "find_spec_drift", "find_pattern", "find_credential_exposure", "check_license_compliance", "find_stale_dependencies", "find_install_script_risk", "find_typosquats", "find_excessive_permissions", "layer_bom"];
19
+ export declare const toolModule: CircleIrAiToolModule;
20
+ export default toolModule;
21
+ export { DETERMINISTIC, llmProvenance } from './result.js';
22
+ export { llmEnabled } from './types.js';
23
+ export type { CircleIrAiToolModule, ModuleContext, ModuleEnablement } from './types.js';
24
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EAAE,oBAAoB,EAAiB,MAAM,YAAY,CAAC;AAsBtE,8DAA8D;AAC9D,eAAO,MAAM,UAAU,sPAWb,CAAC;AAEX,eAAO,MAAM,UAAU,EAAE,oBAuBxB,CAAC;AAEF,eAAe,UAAU,CAAC;AAE1B,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,YAAY,EAAE,oBAAoB,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * `circle-ir-ai/mcp` — this library's tools as a module for the one MCP
3
+ * server.
4
+ *
5
+ * `@cognium/mcp-server` looks for this entry when it starts and, if the
6
+ * package is installed and built against the same `circle-ir` minor,
7
+ * registers these tools after its own. The server is not a dependency of
8
+ * this package and is never bundled with it: the module only describes
9
+ * itself and registers handlers over this library's own functions.
10
+ *
11
+ * Nine of the ten tools are deterministic. `find_credential_exposure` is
12
+ * deterministic unless it is called with `llm_verify`, which asks a model to
13
+ * re-check the candidates; that path runs only when asked for by name, only
14
+ * on an install that is enabled for it, and refuses otherwise.
15
+ */
16
+ import { createRequire } from 'node:module';
17
+ import { registerVerifySpecConformance } from './tools/verify-spec-conformance.js';
18
+ import { registerFindSpecDrift } from './tools/find-spec-drift.js';
19
+ import { registerFindPattern } from './tools/find-pattern.js';
20
+ import { registerFindCredentialExposure } from './tools/find-credential-exposure.js';
21
+ import { registerCheckLicenseCompliance } from './tools/check-license-compliance.js';
22
+ import { registerFindStaleDependencies } from './tools/find-stale-dependencies.js';
23
+ import { registerFindInstallScriptRisk } from './tools/find-install-script-risk.js';
24
+ import { registerFindTyposquats } from './tools/find-typosquats.js';
25
+ import { registerFindExcessivePermissions } from './tools/find-excessive-permissions.js';
26
+ import { registerLayerBom } from './tools/layer-bom.js';
27
+ // From the manifest, so the module can never announce a version or a
28
+ // `circle-ir` pin other than the one it was published with.
29
+ const manifest = createRequire(import.meta.url)('../../package.json');
30
+ /** The tools this module registers, in registration order. */
31
+ export const TOOL_NAMES = [
32
+ 'verify_spec_conformance',
33
+ 'find_spec_drift',
34
+ 'find_pattern',
35
+ 'find_credential_exposure',
36
+ 'check_license_compliance',
37
+ 'find_stale_dependencies',
38
+ 'find_install_script_risk',
39
+ 'find_typosquats',
40
+ 'find_excessive_permissions',
41
+ 'layer_bom',
42
+ ];
43
+ export const toolModule = {
44
+ id: 'circle-ir-ai/mcp',
45
+ version: manifest.version,
46
+ licence: manifest.license,
47
+ circleIrRange: manifest.dependencies['circle-ir'],
48
+ register(server, ctx) {
49
+ // Spec tools
50
+ registerVerifySpecConformance(server);
51
+ registerFindSpecDrift(server);
52
+ registerFindPattern(server);
53
+ // Supply chain and credentials
54
+ registerFindCredentialExposure(server, ctx);
55
+ registerCheckLicenseCompliance(server);
56
+ registerFindStaleDependencies(server);
57
+ registerFindInstallScriptRisk(server);
58
+ registerFindTyposquats(server);
59
+ registerFindExcessivePermissions(server);
60
+ // Inventory
61
+ registerLayerBom(server);
62
+ },
63
+ };
64
+ export default toolModule;
65
+ export { DETERMINISTIC, llmProvenance } from './result.js';
66
+ export { llmEnabled } from './types.js';
67
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C,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;AACzF,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAQxD,qEAAqE;AACrE,4DAA4D;AAC5D,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,oBAAoB,CAAa,CAAC;AAElF,8DAA8D;AAC9D,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,yBAAyB;IACzB,iBAAiB;IACjB,cAAc;IACd,0BAA0B;IAC1B,0BAA0B;IAC1B,yBAAyB;IACzB,0BAA0B;IAC1B,iBAAiB;IACjB,4BAA4B;IAC5B,WAAW;CACH,CAAC;AAEX,MAAM,CAAC,MAAM,UAAU,GAAyB;IAC9C,EAAE,EAAE,kBAAkB;IACtB,OAAO,EAAE,QAAQ,CAAC,OAAO;IACzB,OAAO,EAAE,QAAQ,CAAC,OAAO;IACzB,aAAa,EAAE,QAAQ,CAAC,YAAY,CAAC,WAAW,CAAC;IAEjD,QAAQ,CAAC,MAAiB,EAAE,GAAkB;QAC5C,aAAa;QACb,6BAA6B,CAAC,MAAM,CAAC,CAAC;QACtC,qBAAqB,CAAC,MAAM,CAAC,CAAC;QAC9B,mBAAmB,CAAC,MAAM,CAAC,CAAC;QAE5B,+BAA+B;QAC/B,8BAA8B,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC5C,8BAA8B,CAAC,MAAM,CAAC,CAAC;QACvC,6BAA6B,CAAC,MAAM,CAAC,CAAC;QACtC,6BAA6B,CAAC,MAAM,CAAC,CAAC;QACtC,sBAAsB,CAAC,MAAM,CAAC,CAAC;QAC/B,gCAAgC,CAAC,MAAM,CAAC,CAAC;QAEzC,YAAY;QACZ,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC3B,CAAC;CACF,CAAC;AAEF,eAAe,UAAU,CAAC;AAE1B,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Pure mappers from the engine's `SpecGapResult` (camelCase) to the MCP
3
+ * boundary shapes (snake_case). Kept side-effect-free so they can be unit
4
+ * tested without spinning up the analyzer.
5
+ *
6
+ * Schema stability: field names here are draft-stable through 2026-08-31.
7
+ * Additive changes are safe; renames/removals are breaking (bump major).
8
+ */
9
+ import type { SpecGapResult } from '../spec-gap/index.js';
10
+ /** Confidence at/above which a covered match is "covered" vs "partial". */
11
+ export declare const PARTIAL_CONFIDENCE_THRESHOLD = 0.7;
12
+ export type RequirementStatus = 'covered' | 'partial' | 'uncovered';
13
+ export interface RequirementEvidence {
14
+ function?: string;
15
+ file?: string;
16
+ span?: [number, number];
17
+ }
18
+ export interface VerifyRequirement {
19
+ id: string;
20
+ status: RequirementStatus;
21
+ evidence: RequirementEvidence;
22
+ }
23
+ export interface VerifyConformanceResult {
24
+ alignment_score: number;
25
+ requirements: VerifyRequirement[];
26
+ summary: string;
27
+ }
28
+ export type DriftKind = 'code_without_spec' | 'spec_without_code';
29
+ export interface Drift {
30
+ kind: DriftKind;
31
+ location: string;
32
+ suggested_action: string;
33
+ }
34
+ export interface FindSpecDriftResult {
35
+ drifts: Drift[];
36
+ }
37
+ /** Map a `SpecGapResult` to the `verify_spec_conformance` output shape. */
38
+ export declare function toVerifyConformance(result: SpecGapResult): VerifyConformanceResult;
39
+ /** Map a `SpecGapResult` to the `find_spec_drift` output shape. */
40
+ export declare function toSpecDrift(result: SpecGapResult): FindSpecDriftResult;
41
+ //# sourceMappingURL=mappers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mappers.d.ts","sourceRoot":"","sources":["../../src/mcp/mappers.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,2EAA2E;AAC3E,eAAO,MAAM,4BAA4B,MAAM,CAAC;AAEhD,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,CAAC;AAEpE,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,iBAAiB,CAAC;IAC1B,QAAQ,EAAE,mBAAmB,CAAC;CAC/B;AAED,MAAM,WAAW,uBAAuB;IACtC,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,iBAAiB,EAAE,CAAC;IAClC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,SAAS,GAAG,mBAAmB,GAAG,mBAAmB,CAAC;AAElE,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,KAAK,EAAE,CAAC;CACjB;AAED,2EAA2E;AAC3E,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,GAAG,uBAAuB,CA2ClF;AAED,mEAAmE;AACnE,wBAAgB,WAAW,CAAC,MAAM,EAAE,aAAa,GAAG,mBAAmB,CAqBtE"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Pure mappers from the engine's `SpecGapResult` (camelCase) to the MCP
3
+ * boundary shapes (snake_case). Kept side-effect-free so they can be unit
4
+ * tested without spinning up the analyzer.
5
+ *
6
+ * Schema stability: field names here are draft-stable through 2026-08-31.
7
+ * Additive changes are safe; renames/removals are breaking (bump major).
8
+ */
9
+ /** Confidence at/above which a covered match is "covered" vs "partial". */
10
+ export const PARTIAL_CONFIDENCE_THRESHOLD = 0.7;
11
+ /** Map a `SpecGapResult` to the `verify_spec_conformance` output shape. */
12
+ export function toVerifyConformance(result) {
13
+ // Empty-spec guard: the engine returns specAlignmentScore=100 when zero
14
+ // requirements parse from spec_dir (a missing/empty/malformed spec). A
15
+ // consumer gating on `alignment_score >= N` would treat that as a pass.
16
+ // Surface it as a non-passing 0 with an explicit summary instead.
17
+ if (result.summary.totalRequirements === 0) {
18
+ return {
19
+ alignment_score: 0,
20
+ requirements: [],
21
+ summary: 'No requirements parsed from spec_dir — check the path and that ' +
22
+ 'spec.md uses "- REQ-NNN: ..." bullets.',
23
+ };
24
+ }
25
+ const requirements = [];
26
+ for (const match of result.coveredRequirements) {
27
+ requirements.push({
28
+ id: match.requirement.id,
29
+ status: match.confidence >= PARTIAL_CONFIDENCE_THRESHOLD ? 'covered' : 'partial',
30
+ evidence: { function: match.matchedFunction },
31
+ });
32
+ }
33
+ for (const uncovered of result.uncoveredRequirements) {
34
+ requirements.push({
35
+ id: uncovered.requirement.id,
36
+ status: 'uncovered',
37
+ evidence: {},
38
+ });
39
+ }
40
+ const { covered, totalRequirements, coveragePercent, undocumented } = result.summary;
41
+ const summary = `${covered}/${totalRequirements} requirements covered (${coveragePercent}%); ` +
42
+ `${undocumented} undocumented behaviors`;
43
+ return {
44
+ alignment_score: result.specAlignmentScore,
45
+ requirements,
46
+ summary,
47
+ };
48
+ }
49
+ /** Map a `SpecGapResult` to the `find_spec_drift` output shape. */
50
+ export function toSpecDrift(result) {
51
+ const drifts = [];
52
+ for (const behavior of result.undocumentedBehaviors) {
53
+ drifts.push({
54
+ kind: 'code_without_spec',
55
+ location: behavior.functionName,
56
+ suggested_action: behavior.suggestion,
57
+ });
58
+ }
59
+ for (const uncovered of result.uncoveredRequirements) {
60
+ const { id, description } = uncovered.requirement;
61
+ drifts.push({
62
+ kind: 'spec_without_code',
63
+ location: id,
64
+ suggested_action: uncovered.reason || `Implement ${id}: ${description}`,
65
+ });
66
+ }
67
+ return { drifts };
68
+ }
69
+ //# sourceMappingURL=mappers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mappers.js","sourceRoot":"","sources":["../../src/mcp/mappers.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,2EAA2E;AAC3E,MAAM,CAAC,MAAM,4BAA4B,GAAG,GAAG,CAAC;AAkChD,2EAA2E;AAC3E,MAAM,UAAU,mBAAmB,CAAC,MAAqB;IACvD,wEAAwE;IACxE,uEAAuE;IACvE,wEAAwE;IACxE,kEAAkE;IAClE,IAAI,MAAM,CAAC,OAAO,CAAC,iBAAiB,KAAK,CAAC,EAAE,CAAC;QAC3C,OAAO;YACL,eAAe,EAAE,CAAC;YAClB,YAAY,EAAE,EAAE;YAChB,OAAO,EACL,iEAAiE;gBACjE,wCAAwC;SAC3C,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAAwB,EAAE,CAAC;IAE7C,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,mBAAmB,EAAE,CAAC;QAC/C,YAAY,CAAC,IAAI,CAAC;YAChB,EAAE,EAAE,KAAK,CAAC,WAAW,CAAC,EAAE;YACxB,MAAM,EAAE,KAAK,CAAC,UAAU,IAAI,4BAA4B,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;YAChF,QAAQ,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,eAAe,EAAE;SAC9C,CAAC,CAAC;IACL,CAAC;IAED,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,qBAAqB,EAAE,CAAC;QACrD,YAAY,CAAC,IAAI,CAAC;YAChB,EAAE,EAAE,SAAS,CAAC,WAAW,CAAC,EAAE;YAC5B,MAAM,EAAE,WAAW;YACnB,QAAQ,EAAE,EAAE;SACb,CAAC,CAAC;IACL,CAAC;IAED,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,YAAY,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC;IACrF,MAAM,OAAO,GACX,GAAG,OAAO,IAAI,iBAAiB,0BAA0B,eAAe,MAAM;QAC9E,GAAG,YAAY,yBAAyB,CAAC;IAE3C,OAAO;QACL,eAAe,EAAE,MAAM,CAAC,kBAAkB;QAC1C,YAAY;QACZ,OAAO;KACR,CAAC;AACJ,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,WAAW,CAAC,MAAqB;IAC/C,MAAM,MAAM,GAAY,EAAE,CAAC;IAE3B,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,qBAAqB,EAAE,CAAC;QACpD,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,mBAAmB;YACzB,QAAQ,EAAE,QAAQ,CAAC,YAAY;YAC/B,gBAAgB,EAAE,QAAQ,CAAC,UAAU;SACtC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,qBAAqB,EAAE,CAAC;QACrD,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC,WAAW,CAAC;QAClD,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,mBAAmB;YACzB,QAAQ,EAAE,EAAE;YACZ,gBAAgB,EAAE,SAAS,CAAC,MAAM,IAAI,aAAa,EAAE,KAAK,WAAW,EAAE;SACxE,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,CAAC;AACpB,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * The one result shape every tool in this module returns.
3
+ *
4
+ * Each response says how it was produced: `deterministic`, or
5
+ * `llm: <model>` when a model contributed to it. The field is in the output
6
+ * schema of every tool, so a client can rely on it rather than infer it from
7
+ * which tool it called.
8
+ */
9
+ import { z } from 'zod';
10
+ /** No model was involved in producing the response. */
11
+ export declare const DETERMINISTIC = "deterministic";
12
+ /** The provenance of a response a model contributed to. */
13
+ export declare function llmProvenance(model: string): string;
14
+ export declare const provenanceSchema: z.ZodString;
15
+ export interface ToolResult {
16
+ [key: string]: unknown;
17
+ content: Array<{
18
+ type: 'text';
19
+ text: string;
20
+ }>;
21
+ structuredContent?: Record<string, unknown>;
22
+ isError?: boolean;
23
+ }
24
+ /** A successful result: the payload plus its provenance, as text and as structured content. */
25
+ export declare function toolResult(payload: object, provenance: string): ToolResult;
26
+ /**
27
+ * A refusal: the tool was asked for something this install is not enabled
28
+ * for. One line, as an error result, so the caller sees why — never a quiet
29
+ * fall back to a different behaviour than the one requested.
30
+ */
31
+ export declare function refusal(message: string): ToolResult;
32
+ //# sourceMappingURL=result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../../src/mcp/result.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,uDAAuD;AACvD,eAAO,MAAM,aAAa,kBAAkB,CAAC;AAE7C,2DAA2D;AAC3D,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,eAAO,MAAM,gBAAgB,aAE6E,CAAC;AAE3G,MAAM,WAAW,UAAU;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,+FAA+F;AAC/F,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,UAAU,CAM1E;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAEnD"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * The one result shape every tool in this module returns.
3
+ *
4
+ * Each response says how it was produced: `deterministic`, or
5
+ * `llm: <model>` when a model contributed to it. The field is in the output
6
+ * schema of every tool, so a client can rely on it rather than infer it from
7
+ * which tool it called.
8
+ */
9
+ import { z } from 'zod';
10
+ /** No model was involved in producing the response. */
11
+ export const DETERMINISTIC = 'deterministic';
12
+ /** The provenance of a response a model contributed to. */
13
+ export function llmProvenance(model) {
14
+ return `llm: ${model}`;
15
+ }
16
+ export const provenanceSchema = z
17
+ .string()
18
+ .describe('How this response was produced: "deterministic", or "llm: <model>" when a model contributed');
19
+ /** A successful result: the payload plus its provenance, as text and as structured content. */
20
+ export function toolResult(payload, provenance) {
21
+ const body = { ...payload, provenance };
22
+ return {
23
+ content: [{ type: 'text', text: JSON.stringify(body) }],
24
+ structuredContent: body,
25
+ };
26
+ }
27
+ /**
28
+ * A refusal: the tool was asked for something this install is not enabled
29
+ * for. One line, as an error result, so the caller sees why — never a quiet
30
+ * fall back to a different behaviour than the one requested.
31
+ */
32
+ export function refusal(message) {
33
+ return { content: [{ type: 'text', text: message }], isError: true };
34
+ }
35
+ //# sourceMappingURL=result.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result.js","sourceRoot":"","sources":["../../src/mcp/result.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,uDAAuD;AACvD,MAAM,CAAC,MAAM,aAAa,GAAG,eAAe,CAAC;AAE7C,2DAA2D;AAC3D,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,OAAO,QAAQ,KAAK,EAAE,CAAC;AACzB,CAAC;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC;KAC9B,MAAM,EAAE;KACR,QAAQ,CAAC,6FAA6F,CAAC,CAAC;AAS3G,+FAA+F;AAC/F,MAAM,UAAU,UAAU,CAAC,OAAe,EAAE,UAAkB;IAC5D,MAAM,IAAI,GAAG,EAAE,GAAG,OAAO,EAAE,UAAU,EAAE,CAAC;IACxC,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;QACvD,iBAAiB,EAAE,IAAI;KACxB,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,OAAO,CAAC,OAAe;IACrC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACvE,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * check_license_compliance MCP tool (Pillar I, Workflow #2).
3
+ *
4
+ * Scans a code root for copyleft/restrictive license issues in dependencies.
5
+ * Supports Node.js (package.json) and Rust (Cargo.toml) ecosystems.
6
+ *
7
+ * @see https://github.com/cogniumhq/cognium-ai/issues/79
8
+ */
9
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
10
+ export declare function registerCheckLicenseCompliance(server: McpServer): void;
11
+ //# sourceMappingURL=check-license-compliance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-license-compliance.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/check-license-compliance.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA4HzE,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAmDtE"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * check_license_compliance MCP tool (Pillar I, Workflow #2).
3
+ *
4
+ * Scans a code root for copyleft/restrictive license issues in dependencies.
5
+ * Supports Node.js (package.json) and Rust (Cargo.toml) ecosystems.
6
+ *
7
+ * @see https://github.com/cogniumhq/cognium-ai/issues/79
8
+ */
9
+ import { z } from 'zod';
10
+ import { DETERMINISTIC, provenanceSchema, toolResult } from '../result.js';
11
+ import { scanLicenseCompliance, COPYLEFT_SEVERITY, } from '../../trust/index.js';
12
+ const MAX_FINDINGS = 500;
13
+ const inputSchema = {
14
+ code_root: z.string().describe('Absolute path to the code root to scan'),
15
+ include_dev_deps: z.boolean().optional().default(false).describe('Include devDependencies (default: false)'),
16
+ severity_floor: z.enum(['info', 'low', 'medium', 'high', 'critical']).optional().default('low').describe('Minimum severity to report (default: low)'),
17
+ };
18
+ const findingSchema = z.object({
19
+ kind: z.literal('LICENSE_VIOLATION'),
20
+ severity: z.enum(['low', 'medium', 'high', 'critical']),
21
+ location: z.object({
22
+ file: z.string(),
23
+ span: z.tuple([z.number(), z.number()]),
24
+ }),
25
+ evidence: z.object({
26
+ rule_id: z.string(),
27
+ dependency: z.string(),
28
+ license: z.string(),
29
+ confidence: z.number(),
30
+ }),
31
+ suggested_action: z.string(),
32
+ });
33
+ const outputSchema = {
34
+ findings: z.array(findingSchema),
35
+ summary: z.object({
36
+ total: z.number(),
37
+ by_severity: z.object({
38
+ critical: z.number(),
39
+ high: z.number(),
40
+ medium: z.number(),
41
+ low: z.number(),
42
+ }),
43
+ by_ecosystem: z.object({
44
+ nodejs: z.number(),
45
+ rust: z.number(),
46
+ }),
47
+ truncated: z.boolean(),
48
+ }),
49
+ copyleft_reference: z.record(z.string(), z.string()).describe('Reference table: license to severity'),
50
+ provenance: provenanceSchema,
51
+ };
52
+ const SEVERITY_ORDER = {
53
+ info: 0,
54
+ low: 1,
55
+ medium: 2,
56
+ high: 3,
57
+ critical: 4,
58
+ };
59
+ function licenseToFinding(finding) {
60
+ return {
61
+ kind: 'LICENSE_VIOLATION',
62
+ severity: finding.severity === 'info' ? 'low' : finding.severity,
63
+ location: {
64
+ file: finding.file,
65
+ span: [finding.line ?? 1, finding.line ?? 1],
66
+ },
67
+ evidence: {
68
+ rule_id: finding.ruleId,
69
+ dependency: finding.dependency,
70
+ license: finding.license,
71
+ confidence: finding.confidence,
72
+ },
73
+ suggested_action: finding.suggestedAction,
74
+ };
75
+ }
76
+ function buildCopyleftReference() {
77
+ const ref = {};
78
+ for (const [license, severity] of Object.entries(COPYLEFT_SEVERITY)) {
79
+ ref[license] = severity;
80
+ }
81
+ return ref;
82
+ }
83
+ export function registerCheckLicenseCompliance(server) {
84
+ server.registerTool('check_license_compliance', {
85
+ title: 'Check License Compliance',
86
+ description: 'Scan a code root for copyleft/restrictive license issues in dependencies. ' +
87
+ 'Supports Node.js (package.json) and Rust (Cargo.toml). ' +
88
+ 'Flags AGPL, GPL, LGPL, MPL, and other copyleft licenses with severity classification. ' +
89
+ 'Returns findings with dependency info, license SPDX, and remediation guidance.',
90
+ inputSchema,
91
+ outputSchema,
92
+ }, async ({ code_root, include_dev_deps, severity_floor }) => {
93
+ const scanResult = await scanLicenseCompliance(code_root, {
94
+ includeDevDeps: include_dev_deps,
95
+ minSeverity: severity_floor,
96
+ });
97
+ const floorValue = SEVERITY_ORDER[severity_floor ?? 'low'];
98
+ const filteredFindings = scanResult.findings.filter((f) => SEVERITY_ORDER[f.severity] >= floorValue);
99
+ const truncated = filteredFindings.length > MAX_FINDINGS;
100
+ const findings = filteredFindings
101
+ .slice(0, MAX_FINDINGS)
102
+ .map(licenseToFinding);
103
+ const result = {
104
+ findings,
105
+ summary: {
106
+ total: filteredFindings.length,
107
+ by_severity: {
108
+ critical: filteredFindings.filter((f) => f.severity === 'critical').length,
109
+ high: filteredFindings.filter((f) => f.severity === 'high').length,
110
+ medium: filteredFindings.filter((f) => f.severity === 'medium').length,
111
+ low: filteredFindings.filter((f) => f.severity === 'low').length,
112
+ },
113
+ by_ecosystem: {
114
+ nodejs: filteredFindings.filter((f) => f.ecosystem === 'nodejs').length,
115
+ rust: filteredFindings.filter((f) => f.ecosystem === 'rust').length,
116
+ },
117
+ truncated,
118
+ },
119
+ copyleft_reference: buildCopyleftReference(),
120
+ };
121
+ return toolResult(result, DETERMINISTIC);
122
+ });
123
+ }
124
+ //# sourceMappingURL=check-license-compliance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-license-compliance.js","sourceRoot":"","sources":["../../../src/mcp/tools/check-license-compliance.ts"],"names":[],"mappings":"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"}