@cognium/mcp-server 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.
Files changed (88) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/LICENSE +21 -0
  3. package/README.md +107 -0
  4. package/dist/cache.d.ts +46 -0
  5. package/dist/cache.d.ts.map +1 -0
  6. package/dist/cache.js +106 -0
  7. package/dist/cache.js.map +1 -0
  8. package/dist/index.d.ts +12 -0
  9. package/dist/index.d.ts.map +1 -0
  10. package/dist/index.js +24 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/resources/catalogs.d.ts +63 -0
  13. package/dist/resources/catalogs.d.ts.map +1 -0
  14. package/dist/resources/catalogs.js +92 -0
  15. package/dist/resources/catalogs.js.map +1 -0
  16. package/dist/resources/index.d.ts +13 -0
  17. package/dist/resources/index.d.ts.map +1 -0
  18. package/dist/resources/index.js +94 -0
  19. package/dist/resources/index.js.map +1 -0
  20. package/dist/resources/schema.d.ts +81 -0
  21. package/dist/resources/schema.d.ts.map +1 -0
  22. package/dist/resources/schema.js +63 -0
  23. package/dist/resources/schema.js.map +1 -0
  24. package/dist/server.d.ts +12 -0
  25. package/dist/server.d.ts.map +1 -0
  26. package/dist/server.js +41 -0
  27. package/dist/server.js.map +1 -0
  28. package/dist/tools/attack-surface-summary.d.ts +24 -0
  29. package/dist/tools/attack-surface-summary.d.ts.map +1 -0
  30. package/dist/tools/attack-surface-summary.js +116 -0
  31. package/dist/tools/attack-surface-summary.js.map +1 -0
  32. package/dist/tools/check-sanitizer.d.ts +29 -0
  33. package/dist/tools/check-sanitizer.d.ts.map +1 -0
  34. package/dist/tools/check-sanitizer.js +82 -0
  35. package/dist/tools/check-sanitizer.js.map +1 -0
  36. package/dist/tools/describe-sink.d.ts +22 -0
  37. package/dist/tools/describe-sink.d.ts.map +1 -0
  38. package/dist/tools/describe-sink.js +47 -0
  39. package/dist/tools/describe-sink.js.map +1 -0
  40. package/dist/tools/describe-source.d.ts +27 -0
  41. package/dist/tools/describe-source.d.ts.map +1 -0
  42. package/dist/tools/describe-source.js +64 -0
  43. package/dist/tools/describe-source.js.map +1 -0
  44. package/dist/tools/explain-finding.d.ts +23 -0
  45. package/dist/tools/explain-finding.d.ts.map +1 -0
  46. package/dist/tools/explain-finding.js +65 -0
  47. package/dist/tools/explain-finding.js.map +1 -0
  48. package/dist/tools/find-similar.d.ts +34 -0
  49. package/dist/tools/find-similar.d.ts.map +1 -0
  50. package/dist/tools/find-similar.js +107 -0
  51. package/dist/tools/find-similar.js.map +1 -0
  52. package/dist/tools/list-entry-points.d.ts +22 -0
  53. package/dist/tools/list-entry-points.d.ts.map +1 -0
  54. package/dist/tools/list-entry-points.js +71 -0
  55. package/dist/tools/list-entry-points.js.map +1 -0
  56. package/dist/tools/list-reachable-sinks.d.ts +33 -0
  57. package/dist/tools/list-reachable-sinks.d.ts.map +1 -0
  58. package/dist/tools/list-reachable-sinks.js +116 -0
  59. package/dist/tools/list-reachable-sinks.js.map +1 -0
  60. package/dist/tools/refresh.d.ts +21 -0
  61. package/dist/tools/refresh.d.ts.map +1 -0
  62. package/dist/tools/refresh.js +39 -0
  63. package/dist/tools/refresh.js.map +1 -0
  64. package/dist/tools/scan.d.ts +42 -0
  65. package/dist/tools/scan.d.ts.map +1 -0
  66. package/dist/tools/scan.js +197 -0
  67. package/dist/tools/scan.js.map +1 -0
  68. package/dist/tools/taint-paths.d.ts +31 -0
  69. package/dist/tools/taint-paths.d.ts.map +1 -0
  70. package/dist/tools/taint-paths.js +55 -0
  71. package/dist/tools/taint-paths.js.map +1 -0
  72. package/dist/tools/types.d.ts +22 -0
  73. package/dist/tools/types.d.ts.map +1 -0
  74. package/dist/tools/types.js +17 -0
  75. package/dist/tools/types.js.map +1 -0
  76. package/dist/util/files.d.ts +33 -0
  77. package/dist/util/files.d.ts.map +1 -0
  78. package/dist/util/files.js +184 -0
  79. package/dist/util/files.js.map +1 -0
  80. package/dist/util/serialize.d.ts +29 -0
  81. package/dist/util/serialize.d.ts.map +1 -0
  82. package/dist/util/serialize.js +42 -0
  83. package/dist/util/serialize.js.map +1 -0
  84. package/dist/util/wasm.d.ts +9 -0
  85. package/dist/util/wasm.d.ts.map +1 -0
  86. package/dist/util/wasm.js +37 -0
  87. package/dist/util/wasm.js.map +1 -0
  88. package/package.json +75 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,39 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@cognium/mcp-server` are documented in this file.
4
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
5
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [0.1.0] - 2026-07-15
8
+
9
+ ### Added
10
+
11
+ - Initial MVP of the Model Context Protocol server for circle-ir.
12
+ - Stdio transport (default) for Claude Desktop / Claude Code / Cursor.
13
+ - `ProjectCache` with mtime-based invalidation and LRU eviction (cap 3
14
+ concurrent project analyses).
15
+ - 11 tools exposing SAST capabilities to LLM clients:
16
+ - `scan` — run full circle-ir analysis on a file or directory.
17
+ - `explain_finding` — CWE metadata + remediation guidance for a single
18
+ finding.
19
+ - `taint_paths` — list cross-file taint flows with optional filters.
20
+ - `list_entry_points` — enumerate Tier-1 attacker-reachable methods.
21
+ - `check_sanitizer` — verify a function is a known sanitizer for a
22
+ sink type.
23
+ - `describe_sink` — metadata about a sink category (CWE, severity,
24
+ remediation).
25
+ - `describe_source` — metadata about a taint source category.
26
+ - `attack_surface_summary` — one-shot codebase attack-surface report.
27
+ - `list_reachable_sinks` — BFS from an entry point to reachable sinks.
28
+ - `find_similar` — cluster findings by shape for bulk triage.
29
+ - `refresh` — invalidate the cache for specific files or the entire
30
+ project.
31
+ - 5 read-only resources:
32
+ - `cognium://sast-finding-schema`
33
+ - `cognium://sink-catalog`
34
+ - `cognium://source-catalog`
35
+ - `cognium://sanitizer-catalog`
36
+ - `cognium://passes`
37
+ - Size-bounded serialization (findings capped at 500 per response,
38
+ string fields truncated at 2 KB, IR graphs omitted).
39
+ - No changes to circle-ir engine — MCP is a strictly additive wrapper.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Cognium Labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,107 @@
1
+ # @cognium/mcp-server
2
+
3
+ Model Context Protocol (MCP) server exposing the [circle-ir](https://www.npmjs.com/package/circle-ir) SAST engine as a set of structured tools and reference resources for LLM agents (Claude Desktop, Claude Code, Cursor, cognium-ai).
4
+
5
+ Ships every deterministic capability of circle-ir — polyglot taint analysis, cross-file taint paths, entry-point enumeration, CWE metadata, sanitizer lookups — as MCP tool calls that an LLM can chain without ever guessing at the SAST engine's internal state.
6
+
7
+ - **Zero LLM in the analysis path.** Every finding this server returns comes from the deterministic circle-ir pipeline. LLM-side reasoning is fed by these tools; it does not decide them.
8
+ - **Cache-first.** The server holds up to 3 recent project analyses in memory, keyed by option-set and invalidated by file `mtime`. Repeated tool calls on the same project are effectively free.
9
+ - **Size-bounded output.** Findings, taint paths, and snippets are truncated at safe defaults so a single tool call cannot blow past a client context window.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ npm install -g @cognium/mcp-server
15
+ ```
16
+
17
+ Or run in-place from this monorepo:
18
+
19
+ ```bash
20
+ cd packages/mcp-server
21
+ npm run build
22
+ node dist/index.js
23
+ ```
24
+
25
+ ## Client configuration
26
+
27
+ ### Claude Desktop
28
+
29
+ Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
30
+
31
+ ```json
32
+ {
33
+ "mcpServers": {
34
+ "cognium": {
35
+ "command": "npx",
36
+ "args": ["-y", "@cognium/mcp-server"]
37
+ }
38
+ }
39
+ }
40
+ ```
41
+
42
+ ### Claude Code
43
+
44
+ ```bash
45
+ claude mcp add cognium -- npx -y @cognium/mcp-server
46
+ ```
47
+
48
+ ### Cursor
49
+
50
+ Add to `~/.cursor/mcp.json`:
51
+
52
+ ```json
53
+ {
54
+ "mcpServers": {
55
+ "cognium": {
56
+ "command": "npx",
57
+ "args": ["-y", "@cognium/mcp-server"]
58
+ }
59
+ }
60
+ }
61
+ ```
62
+
63
+ ## Tools
64
+
65
+ | Tool | Purpose |
66
+ | ---- | ------- |
67
+ | `scan` | Run the full polyglot SAST pipeline on a file or directory. Returns SastFindings + per-file taint flows + cross-file taint paths. |
68
+ | `explain_finding` | Enrich a single finding id with CWE metadata, remediation, CVSS-like score, and sanitizer suggestions. |
69
+ | `taint_paths` | List cross-file taint flows filtered by source file, sink file, or sink type. |
70
+ | `list_entry_points` | Enumerate every attacker-reachable handler (HTTP routes, middlewares, event listeners) grouped by framework. |
71
+ | `list_reachable_sinks` | List every sink of a given category that has a real taint flow reaching it (excludes lexical-only matches). |
72
+ | `attack_surface_summary` | Roll-up: entry points × sinks × cross-file taint paths + top files by finding count. |
73
+ | `check_sanitizer` | Deterministic yes/no on whether a function is a recognized sanitizer for a sink category. |
74
+ | `describe_sink` | CWE, remediation, CVSS-like severity, and sanitizer list for a sink category. |
75
+ | `describe_source` | Every framework API pattern circle-ir treats as a source of a given category. |
76
+ | `find_similar` | Given a finding id, return other findings sharing the same `rule_id` and/or `sink_type`. |
77
+ | `refresh` | Manually invalidate the cache for one project or every project. |
78
+
79
+ ## Resources
80
+
81
+ | URI | Content |
82
+ | --- | ------- |
83
+ | `cognium://sast-finding-schema` | JSON Schema for `SastFinding` |
84
+ | `cognium://sink-catalog` | Every taint sink pattern known to circle-ir |
85
+ | `cognium://source-catalog` | Every taint source pattern |
86
+ | `cognium://sanitizer-catalog` | Every sanitizer entry, indexed by sink type |
87
+ | `cognium://passes` | Contents of circle-ir `docs/PASSES.md` — canonical pass registry |
88
+
89
+ ## Suggested tool-call flow
90
+
91
+ 1. `scan` on the project root to prime the cache and get a summary.
92
+ 2. `attack_surface_summary` for a security-posture overview.
93
+ 3. Iterate over the highest-severity findings with `explain_finding` for CWE context.
94
+ 4. `find_similar` to catch the same pattern elsewhere.
95
+ 5. Before proposing a fix, `check_sanitizer` any proposed wrapper against the target sink type.
96
+
97
+ ## Development
98
+
99
+ ```bash
100
+ npm run build # tsc + chmod +x dist/index.js
101
+ npm run typecheck # tsc --noEmit
102
+ npm test # vitest run (unit + smoke)
103
+ ```
104
+
105
+ ## License
106
+
107
+ MIT
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Project-scoped analysis cache.
3
+ *
4
+ * A long-lived MCP process holds one `ProjectAnalysis` per active project
5
+ * root. Invalidation is mtime-based: on each request we re-index file
6
+ * mtimes and re-run `analyzeProject` only if any file changed. LRU
7
+ * eviction keeps memory bounded when the LLM hops between projects.
8
+ */
9
+ import { type ProjectAnalysis } from 'circle-ir';
10
+ /**
11
+ * Per-project analysis options that participate in the cache key. Two
12
+ * scans with different profiles / disabled passes must not share a cache
13
+ * entry.
14
+ */
15
+ export interface ProjectScanOptions {
16
+ /** Force analysis of a single language. */
17
+ language?: string;
18
+ /** Circle-IR disabled passes (e.g. ['naming-convention']). */
19
+ disabledPasses?: string[];
20
+ /** Cross-file phase wall-time budget in ms. 0 = unlimited. */
21
+ crossFileBudgetMs?: number;
22
+ }
23
+ export declare class ProjectCache {
24
+ private entries;
25
+ private readonly capacity;
26
+ constructor(capacity?: number);
27
+ private cacheKey;
28
+ /**
29
+ * Return a cached analysis if fresh, else run `analyzeProject`. The
30
+ * boolean `cacheHit` in the return value lets tools surface cache
31
+ * behaviour to callers.
32
+ */
33
+ getOrCompute(projectRoot: string, opts: ProjectScanOptions): Promise<{
34
+ analysis: ProjectAnalysis;
35
+ cacheHit: boolean;
36
+ analysisMs: number;
37
+ fileCount: number;
38
+ }>;
39
+ /** Invalidate one specific project (all option-keys) or one specific key. */
40
+ invalidate(projectRoot: string, opts?: ProjectScanOptions): number;
41
+ /** Invalidate every cached project. */
42
+ clear(): number;
43
+ size(): number;
44
+ private evictLRU;
45
+ }
46
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,WAAW,CAAC;AAIjE;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,8DAA8D;IAC9D,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAmBD,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,QAAQ,SAAI;IAIxB,OAAO,CAAC,QAAQ;IAIhB;;;;OAIG;IACG,YAAY,CAChB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC;QAAE,QAAQ,EAAE,eAAe,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IA6CnG,6EAA6E;IAC7E,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,GAAG,MAAM;IAgBlE,uCAAuC;IACvC,KAAK,IAAI,MAAM;IAMf,IAAI,IAAI,MAAM;IAId,OAAO,CAAC,QAAQ;CAOjB"}
package/dist/cache.js ADDED
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Project-scoped analysis cache.
3
+ *
4
+ * A long-lived MCP process holds one `ProjectAnalysis` per active project
5
+ * root. Invalidation is mtime-based: on each request we re-index file
6
+ * mtimes and re-run `analyzeProject` only if any file changed. LRU
7
+ * eviction keeps memory bounded when the LLM hops between projects.
8
+ */
9
+ import { resolve } from 'path';
10
+ import { analyzeProject } from 'circle-ir';
11
+ import { collectFiles, indexMtimes, mtimesEqual } from './util/files.js';
12
+ import { ensureAnalyzer } from './util/wasm.js';
13
+ function optionsKey(opts) {
14
+ const parts = [
15
+ `lang=${opts.language ?? '*'}`,
16
+ `disabled=${(opts.disabledPasses ?? []).slice().sort().join(',')}`,
17
+ `budget=${opts.crossFileBudgetMs ?? 'default'}`,
18
+ ];
19
+ return parts.join('|');
20
+ }
21
+ export class ProjectCache {
22
+ entries = new Map();
23
+ capacity;
24
+ constructor(capacity = 3) {
25
+ this.capacity = capacity;
26
+ }
27
+ cacheKey(projectRoot, opts) {
28
+ return `${resolve(projectRoot)}::${optionsKey(opts)}`;
29
+ }
30
+ /**
31
+ * Return a cached analysis if fresh, else run `analyzeProject`. The
32
+ * boolean `cacheHit` in the return value lets tools surface cache
33
+ * behaviour to callers.
34
+ */
35
+ async getOrCompute(projectRoot, opts) {
36
+ await ensureAnalyzer();
37
+ const absRoot = resolve(projectRoot);
38
+ const key = this.cacheKey(absRoot, opts);
39
+ const existing = this.entries.get(key);
40
+ const langOpt = opts.language;
41
+ const currentMtimes = indexMtimes(absRoot, langOpt ? { language: langOpt } : {});
42
+ if (existing && mtimesEqual(existing.mtimes, currentMtimes)) {
43
+ // Touch for LRU: re-insert to move to the end of the Map's iteration order.
44
+ this.entries.delete(key);
45
+ this.entries.set(key, existing);
46
+ return {
47
+ analysis: existing.analysis,
48
+ cacheHit: true,
49
+ analysisMs: existing.analysisMs,
50
+ fileCount: currentMtimes.size,
51
+ };
52
+ }
53
+ const files = collectFiles(absRoot, langOpt ? { language: langOpt } : {});
54
+ const t0 = Date.now();
55
+ const analysis = await analyzeProject(files.map(f => ({ code: f.code, filePath: f.filePath, language: f.language })), {
56
+ ...(opts.disabledPasses ? { disabledPasses: opts.disabledPasses } : {}),
57
+ ...(opts.crossFileBudgetMs !== undefined ? { crossFileBudgetMs: opts.crossFileBudgetMs } : {}),
58
+ });
59
+ const analysisMs = Date.now() - t0;
60
+ const entry = {
61
+ key,
62
+ analysis,
63
+ mtimes: currentMtimes,
64
+ computedAt: Date.now(),
65
+ analysisMs,
66
+ };
67
+ this.entries.set(key, entry);
68
+ this.evictLRU();
69
+ return { analysis, cacheHit: false, analysisMs, fileCount: files.length };
70
+ }
71
+ /** Invalidate one specific project (all option-keys) or one specific key. */
72
+ invalidate(projectRoot, opts) {
73
+ const abs = resolve(projectRoot);
74
+ let removed = 0;
75
+ if (opts) {
76
+ if (this.entries.delete(this.cacheKey(abs, opts)))
77
+ removed++;
78
+ return removed;
79
+ }
80
+ for (const key of [...this.entries.keys()]) {
81
+ if (key.startsWith(abs + '::')) {
82
+ this.entries.delete(key);
83
+ removed++;
84
+ }
85
+ }
86
+ return removed;
87
+ }
88
+ /** Invalidate every cached project. */
89
+ clear() {
90
+ const n = this.entries.size;
91
+ this.entries.clear();
92
+ return n;
93
+ }
94
+ size() {
95
+ return this.entries.size;
96
+ }
97
+ evictLRU() {
98
+ while (this.entries.size > this.capacity) {
99
+ const oldestKey = this.entries.keys().next().value;
100
+ if (oldestKey === undefined)
101
+ break;
102
+ this.entries.delete(oldestKey);
103
+ }
104
+ }
105
+ }
106
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Entry point for the `@cognium/mcp-server` binary. Wires the MCP
4
+ * server to stdio transport — the transport every MCP client (Claude
5
+ * Desktop, Claude Code, Cursor) speaks by default.
6
+ *
7
+ * WASM initialization is deferred to first tool invocation so that
8
+ * `mcp-server-cognium-dev --version` and the initial handshake do not
9
+ * pay the ~200ms tree-sitter cost.
10
+ */
11
+ export {};
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG"}
package/dist/index.js ADDED
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Entry point for the `@cognium/mcp-server` binary. Wires the MCP
4
+ * server to stdio transport — the transport every MCP client (Claude
5
+ * Desktop, Claude Code, Cursor) speaks by default.
6
+ *
7
+ * WASM initialization is deferred to first tool invocation so that
8
+ * `mcp-server-cognium-dev --version` and the initial handshake do not
9
+ * pay the ~200ms tree-sitter cost.
10
+ */
11
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
12
+ import { buildServer } from './server.js';
13
+ async function main() {
14
+ const server = buildServer();
15
+ const transport = new StdioServerTransport();
16
+ await server.connect(transport);
17
+ }
18
+ main().catch((err) => {
19
+ // stderr is safe for stdio-transport servers (stdout is reserved for
20
+ // MCP messages).
21
+ process.stderr.write(`[mcp-server-cognium-dev] fatal: ${err.stack ?? err}\n`);
22
+ process.exit(1);
23
+ });
24
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC;IAC7B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,qEAAqE;IACrE,iBAAiB;IACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mCAAoC,GAAa,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC,CAAC;IACzF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Catalog loaders — expose circle-ir's embedded taint sources / sinks /
3
+ * sanitizers in a shape that MCP tools and resources can consume.
4
+ *
5
+ * We deliberately re-export the in-memory `DEFAULT_*` arrays from
6
+ * `circle-ir` rather than reading the YAML/JSON config files off disk.
7
+ * The defaults are the exact source of truth used at analysis time and
8
+ * are always in sync with the installed version of the analyzer.
9
+ */
10
+ import { type SinkType, type SourceType } from 'circle-ir';
11
+ /**
12
+ * Normalized sanitizer catalog entry consumed by `check_sanitizer` and
13
+ * `describe_sink` tools.
14
+ */
15
+ export interface SanitizerCatalogEntry {
16
+ /** Function / method names or `Class.method` combos that neutralize taint. */
17
+ patterns: string[];
18
+ /**
19
+ * Restrict this entry to a specific sink category. `undefined` means the
20
+ * sanitizer applies to every sink type it covers (`removes` list).
21
+ */
22
+ sinkType?: string;
23
+ /** Optional language restriction (not currently distinguished in defaults). */
24
+ language?: string;
25
+ /** Provenance label — always `circle-ir:default` for embedded defaults. */
26
+ source: string;
27
+ /** Free-form note from the underlying pattern definition. */
28
+ note?: string;
29
+ }
30
+ export interface SinkCatalogEntry {
31
+ method: string;
32
+ class?: string;
33
+ type: SinkType;
34
+ cwe: string;
35
+ severity: string;
36
+ argPositions: number[];
37
+ languages?: string[];
38
+ note?: string;
39
+ }
40
+ export interface SourceCatalogEntry {
41
+ method?: string;
42
+ class?: string;
43
+ property?: string;
44
+ object?: string;
45
+ annotation?: string;
46
+ methodAnnotation?: string;
47
+ type: SourceType;
48
+ severity: string;
49
+ returnTainted?: boolean;
50
+ paramTainted?: boolean;
51
+ propertyTainted?: boolean;
52
+ languages?: string[];
53
+ note?: string;
54
+ }
55
+ /**
56
+ * Return the normalized sanitizer catalog. One catalog entry is produced
57
+ * per `<pattern, sink-type>` combination so downstream filters can match
58
+ * on `sinkType` cheaply.
59
+ */
60
+ export declare function loadSanitizerCatalog(): SanitizerCatalogEntry[];
61
+ export declare function loadSinkCatalog(): SinkCatalogEntry[];
62
+ export declare function loadSourceCatalog(): SourceCatalogEntry[];
63
+ //# sourceMappingURL=catalogs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalogs.d.ts","sourceRoot":"","sources":["../../src/resources/catalogs.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAIL,KAAK,QAAQ,EACb,KAAK,UAAU,EAChB,MAAM,WAAW,CAAC;AAEnB;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,8EAA8E;IAC9E,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,QAAQ,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,qBAAqB,EAAE,CAiC9D;AAED,wBAAgB,eAAe,IAAI,gBAAgB,EAAE,CAapD;AAED,wBAAgB,iBAAiB,IAAI,kBAAkB,EAAE,CAkBxD"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Catalog loaders — expose circle-ir's embedded taint sources / sinks /
3
+ * sanitizers in a shape that MCP tools and resources can consume.
4
+ *
5
+ * We deliberately re-export the in-memory `DEFAULT_*` arrays from
6
+ * `circle-ir` rather than reading the YAML/JSON config files off disk.
7
+ * The defaults are the exact source of truth used at analysis time and
8
+ * are always in sync with the installed version of the analyzer.
9
+ */
10
+ import { DEFAULT_SANITIZERS, DEFAULT_SOURCES, DEFAULT_SINKS, } from 'circle-ir';
11
+ let sanitizerCache = null;
12
+ let sinkCache = null;
13
+ let sourceCache = null;
14
+ /**
15
+ * Return the normalized sanitizer catalog. One catalog entry is produced
16
+ * per `<pattern, sink-type>` combination so downstream filters can match
17
+ * on `sinkType` cheaply.
18
+ */
19
+ export function loadSanitizerCatalog() {
20
+ if (sanitizerCache)
21
+ return sanitizerCache;
22
+ const entries = [];
23
+ for (const s of DEFAULT_SANITIZERS) {
24
+ const patterns = [];
25
+ if (s.method && s.class)
26
+ patterns.push(`${s.class}.${s.method}`);
27
+ if (s.method)
28
+ patterns.push(s.method);
29
+ if (s.class && !s.method)
30
+ patterns.push(s.class);
31
+ if (s.annotation)
32
+ patterns.push(s.annotation);
33
+ if (patterns.length === 0)
34
+ continue;
35
+ const uniquePatterns = [...new Set(patterns)];
36
+ if (s.removes && s.removes.length > 0) {
37
+ for (const sinkType of s.removes) {
38
+ entries.push({
39
+ patterns: uniquePatterns,
40
+ sinkType,
41
+ source: 'circle-ir:default',
42
+ note: s.note,
43
+ });
44
+ }
45
+ }
46
+ else {
47
+ entries.push({
48
+ patterns: uniquePatterns,
49
+ source: 'circle-ir:default',
50
+ note: s.note,
51
+ });
52
+ }
53
+ }
54
+ sanitizerCache = entries;
55
+ return entries;
56
+ }
57
+ export function loadSinkCatalog() {
58
+ if (sinkCache)
59
+ return sinkCache;
60
+ sinkCache = DEFAULT_SINKS.map((s) => ({
61
+ method: s.method,
62
+ class: s.class,
63
+ type: s.type,
64
+ cwe: s.cwe,
65
+ severity: s.severity,
66
+ argPositions: s.arg_positions ?? [],
67
+ languages: s.languages,
68
+ note: s.note,
69
+ }));
70
+ return sinkCache;
71
+ }
72
+ export function loadSourceCatalog() {
73
+ if (sourceCache)
74
+ return sourceCache;
75
+ sourceCache = DEFAULT_SOURCES.map((s) => ({
76
+ method: s.method,
77
+ class: s.class,
78
+ property: s.property,
79
+ object: s.object,
80
+ annotation: s.annotation,
81
+ methodAnnotation: s.method_annotation,
82
+ type: s.type,
83
+ severity: s.severity,
84
+ returnTainted: s.return_tainted,
85
+ paramTainted: s.param_tainted,
86
+ propertyTainted: s.property_tainted,
87
+ languages: s.languages,
88
+ note: s.note,
89
+ }));
90
+ return sourceCache;
91
+ }
92
+ //# sourceMappingURL=catalogs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalogs.js","sourceRoot":"","sources":["../../src/resources/catalogs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * MCP resource registration — read-only reference material an LLM can
3
+ * fetch by URI without invoking a tool.
4
+ *
5
+ * cognium://sast-finding-schema → JSON Schema for SastFinding
6
+ * cognium://sink-catalog → every sink pattern circle-ir knows
7
+ * cognium://source-catalog → every source pattern circle-ir knows
8
+ * cognium://sanitizer-catalog → every sanitizer entry
9
+ * cognium://passes → contents of circle-ir docs/PASSES.md
10
+ */
11
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
12
+ export declare function registerResources(server: McpServer): void;
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAsBzE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA+FzD"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * MCP resource registration — read-only reference material an LLM can
3
+ * fetch by URI without invoking a tool.
4
+ *
5
+ * cognium://sast-finding-schema → JSON Schema for SastFinding
6
+ * cognium://sink-catalog → every sink pattern circle-ir knows
7
+ * cognium://source-catalog → every source pattern circle-ir knows
8
+ * cognium://sanitizer-catalog → every sanitizer entry
9
+ * cognium://passes → contents of circle-ir docs/PASSES.md
10
+ */
11
+ import { createRequire } from 'module';
12
+ import { dirname, join } from 'path';
13
+ import { readFileSync } from 'fs';
14
+ import { SAST_FINDING_SCHEMA } from './schema.js';
15
+ import { loadSanitizerCatalog, loadSinkCatalog, loadSourceCatalog, } from './catalogs.js';
16
+ function loadPassesMarkdown() {
17
+ try {
18
+ const require = createRequire(import.meta.url);
19
+ const circleIrPkg = require.resolve('circle-ir/package.json');
20
+ const passesPath = join(dirname(circleIrPkg), 'docs', 'PASSES.md');
21
+ return readFileSync(passesPath, 'utf8');
22
+ }
23
+ catch (err) {
24
+ return `# PASSES.md unavailable\n\nFailed to load from circle-ir install: ${err.message}`;
25
+ }
26
+ }
27
+ export function registerResources(server) {
28
+ server.registerResource('sast-finding-schema', 'cognium://sast-finding-schema', {
29
+ title: 'SastFinding JSON Schema',
30
+ description: 'Canonical JSON Schema for SastFinding objects emitted by circle-ir.',
31
+ mimeType: 'application/schema+json',
32
+ }, async (uri) => ({
33
+ contents: [
34
+ {
35
+ uri: uri.href,
36
+ mimeType: 'application/schema+json',
37
+ text: JSON.stringify(SAST_FINDING_SCHEMA, null, 2),
38
+ },
39
+ ],
40
+ }));
41
+ server.registerResource('sink-catalog', 'cognium://sink-catalog', {
42
+ title: 'Sink catalog',
43
+ description: 'Every taint sink pattern known to circle-ir (method / class / type / cwe / severity / dangerous arg positions).',
44
+ mimeType: 'application/json',
45
+ }, async (uri) => ({
46
+ contents: [
47
+ {
48
+ uri: uri.href,
49
+ mimeType: 'application/json',
50
+ text: JSON.stringify(loadSinkCatalog(), null, 2),
51
+ },
52
+ ],
53
+ }));
54
+ server.registerResource('source-catalog', 'cognium://source-catalog', {
55
+ title: 'Source catalog',
56
+ description: 'Every taint source pattern known to circle-ir (framework API, annotation, property, or DB result).',
57
+ mimeType: 'application/json',
58
+ }, async (uri) => ({
59
+ contents: [
60
+ {
61
+ uri: uri.href,
62
+ mimeType: 'application/json',
63
+ text: JSON.stringify(loadSourceCatalog(), null, 2),
64
+ },
65
+ ],
66
+ }));
67
+ server.registerResource('sanitizer-catalog', 'cognium://sanitizer-catalog', {
68
+ title: 'Sanitizer catalog',
69
+ description: 'Every sanitizer function circle-ir recognizes, indexed by sink type.',
70
+ mimeType: 'application/json',
71
+ }, async (uri) => ({
72
+ contents: [
73
+ {
74
+ uri: uri.href,
75
+ mimeType: 'application/json',
76
+ text: JSON.stringify(loadSanitizerCatalog(), null, 2),
77
+ },
78
+ ],
79
+ }));
80
+ server.registerResource('passes', 'cognium://passes', {
81
+ title: 'Pass + metric registry (PASSES.md)',
82
+ description: 'Canonical pass registry with rule_id, CWE, SARIF level, and status for every circle-ir analysis pass.',
83
+ mimeType: 'text/markdown',
84
+ }, async (uri) => ({
85
+ contents: [
86
+ {
87
+ uri: uri.href,
88
+ mimeType: 'text/markdown',
89
+ text: loadPassesMarkdown(),
90
+ },
91
+ ],
92
+ }));
93
+ }
94
+ //# sourceMappingURL=index.js.map