@guardion/guardion 0.2.0 → 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.
Files changed (89) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +202 -0
  3. package/dist/bin/cli.d.ts.map +1 -0
  4. package/dist/bin/cli.js +590 -0
  5. package/dist/bin/cli.js.map +1 -0
  6. package/dist/connectors/claude-code/hooks/enforce.cjs +58 -0
  7. package/dist/connectors/claude-code/hooks/guardion-hook.cjs +355 -0
  8. package/dist/connectors/claude-code/hooks/tool-scanner.cjs +272 -0
  9. package/dist/connectors/claude-code/src/collect.d.ts +5 -0
  10. package/dist/connectors/claude-code/src/collect.d.ts.map +1 -0
  11. package/dist/connectors/claude-code/src/collect.js +17 -0
  12. package/dist/connectors/claude-code/src/collect.js.map +1 -0
  13. package/dist/{installer.d.ts → connectors/claude-code/src/installer.d.ts} +2 -1
  14. package/dist/connectors/claude-code/src/installer.d.ts.map +1 -0
  15. package/dist/connectors/claude-code/src/installer.js +190 -0
  16. package/dist/connectors/claude-code/src/installer.js.map +1 -0
  17. package/dist/connectors/claude-code/src/scanner.d.ts.map +1 -0
  18. package/dist/{scanner.js → connectors/claude-code/src/scanner.js} +1 -1
  19. package/dist/connectors/claude-code/src/scanner.js.map +1 -0
  20. package/dist/core/config.d.ts +239 -0
  21. package/dist/core/config.d.ts.map +1 -0
  22. package/dist/core/config.js +154 -0
  23. package/dist/core/config.js.map +1 -0
  24. package/dist/{constants.d.ts → core/constants.d.ts} +8 -3
  25. package/dist/core/constants.d.ts.map +1 -0
  26. package/dist/core/constants.js +54 -0
  27. package/dist/core/constants.js.map +1 -0
  28. package/dist/core/discover.d.ts +36 -0
  29. package/dist/core/discover.d.ts.map +1 -0
  30. package/dist/core/discover.js +154 -0
  31. package/dist/core/discover.js.map +1 -0
  32. package/dist/core/fingerprint.cjs +84 -0
  33. package/dist/core/inventory.d.ts +35 -0
  34. package/dist/core/inventory.d.ts.map +1 -0
  35. package/dist/core/inventory.js +69 -0
  36. package/dist/core/inventory.js.map +1 -0
  37. package/dist/core/keychain.d.ts.map +1 -0
  38. package/dist/{keychain.js → core/keychain.js} +53 -15
  39. package/dist/core/keychain.js.map +1 -0
  40. package/dist/core/mcp/guard-client.cjs +86 -0
  41. package/dist/core/mcp/interceptor.cjs +238 -0
  42. package/dist/core/mcp/jsonrpc.cjs +194 -0
  43. package/dist/core/mcp/transport/http-server-side.cjs +89 -0
  44. package/dist/core/mcp/transport/http-upstream.cjs +111 -0
  45. package/dist/core/mcp/transport/http_forward.cjs +40 -0
  46. package/dist/core/mcp/transport/http_input.cjs +46 -0
  47. package/dist/core/mcp/transport/http_reverse.cjs +33 -0
  48. package/dist/core/mcp/transport/index.cjs +32 -0
  49. package/dist/core/mcp/transport/sse_bridge.cjs +101 -0
  50. package/dist/core/mcp/transport/stdio.cjs +60 -0
  51. package/dist/core/mcp-interpose.cjs +141 -0
  52. package/dist/core/mcp-protect.d.ts +69 -0
  53. package/dist/core/mcp-protect.d.ts.map +1 -0
  54. package/dist/core/mcp-protect.js +205 -0
  55. package/dist/core/mcp-protect.js.map +1 -0
  56. package/dist/core/mcp-scan.d.ts +40 -0
  57. package/dist/core/mcp-scan.d.ts.map +1 -0
  58. package/dist/core/mcp-scan.js +201 -0
  59. package/dist/core/mcp-scan.js.map +1 -0
  60. package/dist/core/mock-server.d.ts.map +1 -0
  61. package/dist/{mock-server.js → core/mock-server.js} +60 -4
  62. package/dist/core/mock-server.js.map +1 -0
  63. package/package.json +9 -10
  64. package/config.yaml.example +0 -26
  65. package/dist/cli.d.ts.map +0 -1
  66. package/dist/cli.js +0 -289
  67. package/dist/cli.js.map +0 -1
  68. package/dist/config.d.ts +0 -28
  69. package/dist/config.d.ts.map +0 -1
  70. package/dist/config.js +0 -63
  71. package/dist/config.js.map +0 -1
  72. package/dist/constants.d.ts.map +0 -1
  73. package/dist/constants.js +0 -44
  74. package/dist/constants.js.map +0 -1
  75. package/dist/installer.d.ts.map +0 -1
  76. package/dist/installer.js +0 -137
  77. package/dist/installer.js.map +0 -1
  78. package/dist/keychain.d.ts.map +0 -1
  79. package/dist/keychain.js.map +0 -1
  80. package/dist/mock-server.d.ts.map +0 -1
  81. package/dist/mock-server.js.map +0 -1
  82. package/dist/scanner.d.ts.map +0 -1
  83. package/dist/scanner.js.map +0 -1
  84. package/hooks/guardion-hook.cjs +0 -202
  85. /package/dist/{cli.d.ts → bin/cli.d.ts} +0 -0
  86. /package/dist/{scanner.d.ts → connectors/claude-code/src/scanner.d.ts} +0 -0
  87. /package/dist/{keychain.d.ts → core/keychain.d.ts} +0 -0
  88. /package/{hooks → dist/core}/metadata.cjs +0 -0
  89. /package/dist/{mock-server.d.ts → core/mock-server.d.ts} +0 -0
@@ -0,0 +1,60 @@
1
+ 'use strict';
2
+ /**
3
+ * stdio transport: the host launches us in place of the real server and speaks
4
+ * newline-delimited JSON-RPC over our stdin/stdout; we spawn the real server and
5
+ * relay over its stdin/stdout. This is the default, universal interposer mode.
6
+ *
7
+ * client (host) ⇄ process.stdin / process.stdout
8
+ * server (real) ⇄ child.stdin / child.stdout
9
+ *
10
+ * Channel contract (shared by every transport):
11
+ * sendClient(obj) — emit toward the host
12
+ * sendServer(obj) — emit toward the real server
13
+ * start({ onClient, onServer }) — begin relaying parsed messages; unparseable
14
+ * lines are forwarded verbatim (opaque) so we never corrupt the stream
15
+ * close()
16
+ */
17
+ const { spawn } = require('child_process');
18
+ const J = require('../jsonrpc.cjs');
19
+
20
+ function createStdioChannel(opts) {
21
+ const { target, env, onExit, log = () => {} } = opts;
22
+ if (!Array.isArray(target) || target.length === 0) {
23
+ throw new Error('stdio transport requires a target command after --');
24
+ }
25
+ const child = spawn(target[0], target.slice(1), { stdio: ['pipe', 'pipe', 'inherit'], env: env || process.env });
26
+ child.on('error', (e) => { log(`spawn error: ${e.message}`); process.exit(1); });
27
+ child.on('exit', (code) => { if (onExit) onExit(code); });
28
+
29
+ function sendClient(obj) { process.stdout.write(J.serialize(obj) + '\n'); }
30
+ function sendServer(obj) { try { child.stdin.write(J.serialize(obj) + '\n'); } catch { /* server gone */ } }
31
+ function sendServerRaw(line) { try { child.stdin.write(line + '\n'); } catch { /* server gone */ } }
32
+ function sendClientRaw(line) { process.stdout.write(line + '\n'); }
33
+
34
+ function start(handlers) {
35
+ const inF = new J.LineFramer();
36
+ process.stdin.setEncoding('utf8');
37
+ process.stdin.on('data', (d) => {
38
+ for (const line of inF.push(d)) {
39
+ const msg = J.parse(line);
40
+ if (msg) Promise.resolve(handlers.onClient(msg)).catch(() => {});
41
+ else sendServerRaw(line); // opaque → pass through
42
+ }
43
+ });
44
+ const outF = new J.LineFramer();
45
+ child.stdout.setEncoding('utf8');
46
+ child.stdout.on('data', (d) => {
47
+ for (const line of outF.push(d)) {
48
+ const msg = J.parse(line);
49
+ if (msg) Promise.resolve(handlers.onServer(msg)).catch(() => {});
50
+ else sendClientRaw(line); // opaque → pass through
51
+ }
52
+ });
53
+ }
54
+
55
+ function close() { try { child.kill(); } catch { /* ignore */ } }
56
+
57
+ return { sendClient, sendServer, start, close, child };
58
+ }
59
+
60
+ module.exports = { createStdioChannel };
@@ -0,0 +1,141 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ /**
4
+ * Guardion MCP interposer (Layer 2, AGT MCP-Security-Gateway-1.0 contract).
5
+ *
6
+ * A UNIVERSAL, host-agnostic way to scan every MCP message for ANY agent app that
7
+ * uses MCP servers (Claude Desktop, ChatGPT Desktop, Cursor, Cline, Windsurf, …).
8
+ * It relays JSON-RPC both ways and delegates ALL detection to Guard (POST /v1/guard)
9
+ * — we never re-implement detection here.
10
+ *
11
+ * stdio (default): node mcp-interpose.cjs --server <name> -- <cmd> <args...>
12
+ * http_forward: node mcp-interpose.cjs --server <name> --url https://host/mcp
13
+ * http_input: node mcp-interpose.cjs --server <name> --listen 8900 -- <cmd>
14
+ * http_reverse: node mcp-interpose.cjs --server <name> --listen 8900 --url https://host/mcp
15
+ * sse_bridge: node mcp-interpose.cjs --server <name> --transport sse_bridge --url https://host/sse
16
+ *
17
+ * Scanned (delegated to Guard):
18
+ * • tools/call · resources/read · prompts/get request → INPUT (PreTool)
19
+ * • their results → OUTPUT (PostTool): deny ⇒ error,
20
+ * correction ⇒ in-proxy redaction
21
+ * • sampling/createMessage (server-initiated) → INPUT (host LLM feed)
22
+ * • tools/list result → integrity AT CONNECT: rug-pull (local fingerprint drift)
23
+ * strips changed tools; a Guard deny refuses the poisoned server
24
+ *
25
+ * Zero external deps (node builtins only). Fail-OPEN by default; never blocks the
26
+ * transport on its own errors. Enforcement gated by config.enforce (default off).
27
+ */
28
+ const fs = require('fs');
29
+ const os = require('os');
30
+ const path = require('path');
31
+
32
+ const { createGuardClient } = require('./mcp/guard-client.cjs');
33
+ const { createInterceptor } = require('./mcp/interceptor.cjs');
34
+ const { selectTransport, TRANSPORTS } = require('./mcp/transport/index.cjs');
35
+ let fingerprint = null;
36
+ try { fingerprint = require('./fingerprint.cjs'); } catch { /* pin optional */ }
37
+
38
+ function log(msg) { process.stderr.write(`[guardion] mcp-interpose: ${msg}\n`); }
39
+
40
+ // ── argv parsing: flags before `--`, target command after ────────────────────
41
+ const argv = process.argv.slice(2);
42
+ const dd = argv.indexOf('--');
43
+ const flags = argv.slice(0, dd === -1 ? argv.length : dd);
44
+ const target = dd === -1 ? [] : argv.slice(dd + 1);
45
+
46
+ function flagVal(name) { const i = flags.indexOf(name); return i >= 0 ? (flags[i + 1] || '') : ''; }
47
+ function flagAll(name) { const out = []; for (let i = 0; i < flags.length; i++) if (flags[i] === name) out.push(flags[i + 1] || ''); return out; }
48
+
49
+ const serverName = flagVal('--server');
50
+ const upstreamUrl = flagVal('--url');
51
+ const listenSpec = flagVal('--listen');
52
+ const headerArgs = flagAll('--header'); // 'Authorization: Bearer x'
53
+
54
+ // transport: explicit flag, else inferred from --url / --listen / target.
55
+ function inferTransport() {
56
+ const explicit = flagVal('--transport');
57
+ if (explicit) return explicit;
58
+ if (upstreamUrl && listenSpec) return 'http_reverse';
59
+ if (upstreamUrl) return 'http_forward';
60
+ if (listenSpec && target.length) return 'http_input';
61
+ return 'stdio';
62
+ }
63
+ const transportKind = inferTransport();
64
+ if (!TRANSPORTS.has(transportKind)) { log(`unknown --transport ${transportKind}`); process.exit(1); }
65
+
66
+ // ── config / token (same resolution as the hook) ─────────────────────────────
67
+ function loadConfig() {
68
+ try { return JSON.parse(fs.readFileSync(path.join(os.homedir(), '.guardion', 'config.json'), 'utf8')); } catch { return {}; }
69
+ }
70
+ const cfg = loadConfig();
71
+ const API_URL = process.env.GUARDION_API_URL || cfg.api_url || 'https://api.guardion.ai';
72
+ // --policy flag > env > config. Lets `guardion mcp --policy x` target a policy per server.
73
+ const POLICY = flagVal('--policy') || process.env.GUARDION_POLICY || cfg.policy || undefined;
74
+ const APPLICATION = cfg.application || 'mcp-interpose';
75
+ const TIMEOUT = (cfg.hooks && cfg.hooks.timeout_ms) || 3000;
76
+
77
+ // Mode resolution: an explicit `--mode` (or GUARDION_MODE / cfg.mode) is the single knob
78
+ // the `guardion mcp` command sets; it OVERRIDES the individual env flags.
79
+ // dlp → anonymize via corrections, never block (default)
80
+ // enforce → block on a deny verdict + anonymize
81
+ // monitor → observe-only, fire-and-forget (no modification)
82
+ const MODE = (flagVal('--mode') || process.env.GUARDION_MODE || cfg.mode || '').toLowerCase();
83
+ let ENFORCE = cfg.enforce === true || process.env.GUARDION_ENFORCE === 'true';
84
+ let DLP = cfg.dlp === true || process.env.GUARDION_DLP === 'true';
85
+ if (MODE === 'dlp') { DLP = true; ENFORCE = false; }
86
+ else if (MODE === 'enforce') { ENFORCE = true; }
87
+ else if (MODE === 'monitor' || MODE === 'observe') { DLP = false; ENFORCE = false; }
88
+ const FAIL_CLOSED = cfg.fail_closed === true || process.env.GUARDION_FAIL_CLOSED === 'true';
89
+ const INTEGRITY = cfg.integrity !== false; // default on (tool-list integrity at connect)
90
+ const REDACT = cfg.redact !== false; // default on (in-proxy redaction)
91
+
92
+ function resolveToken() {
93
+ if (process.env.GUARDION_TOKEN) return process.env.GUARDION_TOKEN.trim();
94
+ for (const p of ['/etc/guardion/token', path.join(os.homedir(), '.guardion', 'token')]) {
95
+ try { const t = fs.readFileSync(p, 'utf8').trim(); if (t) return t; } catch { /* absent */ }
96
+ }
97
+ return '';
98
+ }
99
+ const TOKEN = resolveToken();
100
+
101
+ function parseHeaders(items) {
102
+ const h = {};
103
+ for (const it of items) { const i = it.indexOf(':'); if (i > 0) h[it.slice(0, i).trim()] = it.slice(i + 1).trim(); }
104
+ return h;
105
+ }
106
+ function parseListen(spec) {
107
+ if (!spec) return { host: '127.0.0.1', port: 0 };
108
+ const i = spec.lastIndexOf(':');
109
+ if (i > 0) return { host: spec.slice(0, i), port: parseInt(spec.slice(i + 1), 10) || 0 };
110
+ return { host: '127.0.0.1', port: parseInt(spec, 10) || 0 };
111
+ }
112
+
113
+ // ── wire guard client + interceptor + transport ──────────────────────────────
114
+ const guard = createGuardClient({
115
+ apiUrl: API_URL, token: TOKEN, policy: POLICY, application: APPLICATION,
116
+ timeout: TIMEOUT, failClosed: FAIL_CLOSED,
117
+ });
118
+
119
+ const listen = parseListen(listenSpec);
120
+ let channel;
121
+ try {
122
+ channel = selectTransport(transportKind, {
123
+ target, env: process.env, url: upstreamUrl, headers: parseHeaders(headerArgs),
124
+ timeout: 30000, port: listen.port, host: listen.host, mcpPath: '/',
125
+ onExit: (code) => process.exit(code == null ? 0 : code), log,
126
+ });
127
+ } catch (e) { log(e.message); process.exit(1); }
128
+
129
+ const interceptor = createInterceptor({
130
+ guard, enforce: ENFORCE, dlp: DLP, integrity: INTEGRITY, redact: REDACT,
131
+ fingerprint, pinPath: path.join(os.homedir(), '.guardion', 'fingerprints.json'),
132
+ serverName, log,
133
+ sendClient: channel.sendClient, sendServer: channel.sendServer,
134
+ });
135
+
136
+ Promise.resolve(channel.start({ onClient: interceptor.onClient, onServer: interceptor.onServer })).catch((e) => { log(`start error: ${e && e.message}`); });
137
+
138
+ // stdio-host transports without a child exit when the host closes stdin.
139
+ if (transportKind === 'http_forward' || transportKind === 'sse_bridge') {
140
+ process.stdin.on('end', () => process.exit(0));
141
+ }
@@ -0,0 +1,69 @@
1
+ export interface McpServerCfg {
2
+ command?: string;
3
+ args?: string[];
4
+ env?: Record<string, string>;
5
+ url?: string;
6
+ type?: string;
7
+ headers?: Record<string, string>;
8
+ [k: string]: unknown;
9
+ }
10
+ /** npm package that ships the `guardion mcp` wrapper (used in the injected npx prefix). */
11
+ export declare const NPX_PKG = "@guardion/guardion";
12
+ /** Absolute path to the interposer script (lives beside this core module; dist mirrors source). */
13
+ export declare function interposerPath(): string;
14
+ /** Known agent-app MCP config locations (existing ones are acted on). */
15
+ export declare function knownAppConfigs(home?: string, cwd?: string): Array<{
16
+ app: string;
17
+ path: string;
18
+ }>;
19
+ /** The key under which a given config object holds its MCP servers. */
20
+ export declare function serversKey(obj: any): 'mcpServers' | 'servers' | null;
21
+ /** True if a server entry is already pointing at our wrapper (idempotency). Detects
22
+ * both the npx form (`npx -y @guardion/guardion mcp …`) and the local node form. */
23
+ export declare function isWrapped(cfg: McpServerCfg, interposer?: string): boolean;
24
+ /** Pick the interposer transport for a URL server: legacy SSE vs streamable HTTP. */
25
+ export declare function urlTransport(cfg: McpServerCfg): 'sse_bridge' | 'http_forward';
26
+ export interface WrapOpts {
27
+ /** DLP mode baked into the prefix: dlp (default) | enforce | monitor */
28
+ mode?: string;
29
+ /** Optional policy slug for this server */
30
+ policy?: string;
31
+ /** Dev: inject `node <abs>/mcp-interpose.cjs` instead of the npx form */
32
+ local?: boolean;
33
+ nodeBin?: string;
34
+ interposer?: string;
35
+ }
36
+ /** Wrap one MCP server config so the host launches `guardion mcp` + the real server.
37
+ * By default the prefix is the npx form (`npx -y @guardion/guardion mcp …`) so no
38
+ * global install is needed; `--local` injects the repo's interposer directly. stdio
39
+ * servers keep the `-- cmd args` form; URL servers bridge over http_forward / sse_bridge
40
+ * so they get the same governance instead of being skipped. */
41
+ export declare function wrapServer(name: string, original: McpServerCfg, opts?: WrapOpts): McpServerCfg;
42
+ export interface RewriteResult {
43
+ obj: any;
44
+ wrapped: string[];
45
+ skipped: string[];
46
+ }
47
+ /** Pure: rewrite all MCP servers in a parsed config object. Both stdio (command)
48
+ * and URL (http/sse) servers are wrapped — URL servers bridge through the
49
+ * interposer over http_forward / sse_bridge. Idempotent. */
50
+ export declare function rewriteServers(obj: any, opts?: WrapOpts): RewriteResult;
51
+ /** Restore a config object: unwrap any interposer-wrapped servers back to original. */
52
+ export declare function unwrapServers(obj: any, interposer?: string): RewriteResult;
53
+ export interface ProtectFileResult {
54
+ app: string;
55
+ path: string;
56
+ wrapped: string[];
57
+ skipped: string[];
58
+ error?: string;
59
+ }
60
+ /** Protect a single config file (backup + rewrite). Best-effort; never throws. */
61
+ export declare function protectFile(app: string, file: string, dryRun?: boolean, opts?: WrapOpts): ProtectFileResult;
62
+ /** Revert a single config file from its backup (or unwrap in place). */
63
+ export declare function revertFile(app: string, file: string): ProtectFileResult;
64
+ /** Protect (or --revert) every discovered agent-app MCP config. */
65
+ export declare function protectAll(opts?: {
66
+ revert?: boolean;
67
+ dryRun?: boolean;
68
+ } & WrapOpts): ProtectFileResult[];
69
+ //# sourceMappingURL=mcp-protect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-protect.d.ts","sourceRoot":"","sources":["../../core/mcp-protect.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9D,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AAED,2FAA2F;AAC3F,eAAO,MAAM,OAAO,uBAAuB,CAAC;AAE5C,mGAAmG;AACnG,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,yEAAyE;AACzE,wBAAgB,eAAe,CAAC,IAAI,SAAe,EAAE,GAAG,SAAgB,GAAG,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAY9G;AAED,uEAAuE;AACvE,wBAAgB,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,YAAY,GAAG,SAAS,GAAG,IAAI,CAIpE;AAED;qFACqF;AACrF,wBAAgB,SAAS,CAAC,GAAG,EAAE,YAAY,EAAE,UAAU,SAAmB,GAAG,OAAO,CAKnF;AAED,qFAAqF;AACrF,wBAAgB,YAAY,CAAC,GAAG,EAAE,YAAY,GAAG,YAAY,GAAG,cAAc,CAK7E;AAUD,MAAM,WAAW,QAAQ;IACvB,wEAAwE;IACxE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;gEAIgE;AAChE,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,IAAI,GAAE,QAAa,GAAG,YAAY,CAalG;AAED,MAAM,WAAW,aAAa;IAAG,GAAG,EAAE,GAAG,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE;AAEjF;;6DAE6D;AAC7D,wBAAgB,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,GAAE,QAAa,GAAG,aAAa,CAc3E;AAED,uFAAuF;AACvF,wBAAgB,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,UAAU,SAAmB,GAAG,aAAa,CA+BpF;AAID,MAAM,WAAW,iBAAiB;IAAG,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE;AAEtH,kFAAkF;AAClF,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,UAAQ,EAAE,IAAI,GAAE,QAAa,GAAG,iBAAiB,CAa7G;AAED,wEAAwE;AACxE,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAevE;AAED,mEAAmE;AACnE,wBAAgB,UAAU,CACxB,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,QAAa,GAC3D,iBAAiB,EAAE,CAIrB"}
@@ -0,0 +1,205 @@
1
+ // `guardion mcp-protect` — universal MCP interposition install. Discovers the MCP
2
+ // config of every agent app on this machine (Claude Desktop, ChatGPT Desktop,
3
+ // Cursor, Cline, Windsurf, VS Code, Claude Code, project .mcp.json) and rewrites
4
+ // each stdio MCP server so the host launches the Guardion interposer
5
+ // (hooks/mcp-interpose.cjs) wrapping the real server — so every MCP tool
6
+ // input/output is scanned for ANY host, no per-app hook required.
7
+ import fs from 'node:fs';
8
+ import os from 'node:os';
9
+ import path from 'node:path';
10
+ import { fileURLToPath } from 'node:url';
11
+ /** npm package that ships the `guardion mcp` wrapper (used in the injected npx prefix). */
12
+ export const NPX_PKG = '@guardion/guardion';
13
+ /** Absolute path to the interposer script (lives beside this core module; dist mirrors source). */
14
+ export function interposerPath() {
15
+ return path.resolve(path.dirname(fileURLToPath(import.meta.url)), 'mcp-interpose.cjs');
16
+ }
17
+ /** Known agent-app MCP config locations (existing ones are acted on). */
18
+ export function knownAppConfigs(home = os.homedir(), cwd = process.cwd()) {
19
+ const appSup = path.join(home, 'Library', 'Application Support'); // macOS
20
+ return [
21
+ { app: 'Claude Desktop', path: path.join(appSup, 'Claude', 'claude_desktop_config.json') },
22
+ { app: 'ChatGPT Desktop', path: path.join(appSup, 'ChatGPT', 'mcp.json') },
23
+ { app: 'Cursor', path: path.join(home, '.cursor', 'mcp.json') },
24
+ { app: 'Windsurf', path: path.join(home, '.codeium', 'windsurf', 'mcp_config.json') },
25
+ { app: 'Cline', path: path.join(appSup, 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json') },
26
+ { app: 'Claude Code', path: path.join(home, '.claude.json') },
27
+ { app: 'VS Code (project)', path: path.join(cwd, '.vscode', 'mcp.json') },
28
+ { app: 'Project .mcp.json', path: path.join(cwd, '.mcp.json') },
29
+ ];
30
+ }
31
+ /** The key under which a given config object holds its MCP servers. */
32
+ export function serversKey(obj) {
33
+ if (obj && typeof obj.mcpServers === 'object')
34
+ return 'mcpServers';
35
+ if (obj && typeof obj.servers === 'object')
36
+ return 'servers';
37
+ return null;
38
+ }
39
+ /** True if a server entry is already pointing at our wrapper (idempotency). Detects
40
+ * both the npx form (`npx -y @guardion/guardion mcp …`) and the local node form. */
41
+ export function isWrapped(cfg, interposer = interposerPath()) {
42
+ if (!cfg || !Array.isArray(cfg.args))
43
+ return false;
44
+ return cfg.args.includes(interposer)
45
+ || cfg.args.includes(NPX_PKG)
46
+ || cfg.args.some((a) => typeof a === 'string' && a.endsWith('mcp-interpose.cjs'));
47
+ }
48
+ /** Pick the interposer transport for a URL server: legacy SSE vs streamable HTTP. */
49
+ export function urlTransport(cfg) {
50
+ const t = String(cfg.type || '').toLowerCase();
51
+ const url = String(cfg.url || '');
52
+ if (t === 'sse' || /\/sse(\b|\/|\?|$)/.test(url))
53
+ return 'sse_bridge';
54
+ return 'http_forward';
55
+ }
56
+ /** Header config (object) → repeated `--header 'K: V'` interposer flags. */
57
+ function headerFlags(headers) {
58
+ if (!headers || typeof headers !== 'object')
59
+ return [];
60
+ const out = [];
61
+ for (const [k, v] of Object.entries(headers))
62
+ out.push('--header', `${k}: ${v}`);
63
+ return out;
64
+ }
65
+ /** Wrap one MCP server config so the host launches `guardion mcp` + the real server.
66
+ * By default the prefix is the npx form (`npx -y @guardion/guardion mcp …`) so no
67
+ * global install is needed; `--local` injects the repo's interposer directly. stdio
68
+ * servers keep the `-- cmd args` form; URL servers bridge over http_forward / sse_bridge
69
+ * so they get the same governance instead of being skipped. */
70
+ export function wrapServer(name, original, opts = {}) {
71
+ const mode = opts.mode || 'dlp';
72
+ const wrapArgs = ['--mode', mode, '--server', name];
73
+ if (opts.policy)
74
+ wrapArgs.push('--policy', opts.policy);
75
+ if (original.url) {
76
+ wrapArgs.push('--transport', urlTransport(original), '--url', String(original.url), ...headerFlags(original.headers));
77
+ }
78
+ else {
79
+ wrapArgs.push('--', original.command, ...(original.args || []));
80
+ }
81
+ const launch = opts.local
82
+ ? { command: opts.nodeBin || process.execPath, args: [opts.interposer || interposerPath(), ...wrapArgs] }
83
+ : { command: 'npx', args: ['-y', NPX_PKG, 'mcp', ...wrapArgs] };
84
+ return { ...launch, ...(original.env ? { env: original.env } : {}) };
85
+ }
86
+ /** Pure: rewrite all MCP servers in a parsed config object. Both stdio (command)
87
+ * and URL (http/sse) servers are wrapped — URL servers bridge through the
88
+ * interposer over http_forward / sse_bridge. Idempotent. */
89
+ export function rewriteServers(obj, opts = {}) {
90
+ const key = serversKey(obj);
91
+ const wrapped = [];
92
+ const skipped = [];
93
+ if (!key)
94
+ return { obj, wrapped, skipped };
95
+ const servers = obj[key];
96
+ const out = {};
97
+ for (const [name, cfg] of Object.entries(servers)) {
98
+ if (!cfg || typeof cfg !== 'object') {
99
+ out[name] = cfg;
100
+ continue;
101
+ }
102
+ if (isWrapped(cfg)) {
103
+ out[name] = cfg;
104
+ continue;
105
+ } // already protected
106
+ if (!cfg.command && !cfg.url) {
107
+ out[name] = cfg;
108
+ skipped.push(name);
109
+ continue;
110
+ }
111
+ out[name] = wrapServer(name, cfg, opts);
112
+ wrapped.push(name);
113
+ }
114
+ return { obj: { ...obj, [key]: out }, wrapped, skipped };
115
+ }
116
+ /** Restore a config object: unwrap any interposer-wrapped servers back to original. */
117
+ export function unwrapServers(obj, interposer = interposerPath()) {
118
+ const key = serversKey(obj);
119
+ const wrapped = [];
120
+ const skipped = [];
121
+ if (!key)
122
+ return { obj, wrapped, skipped };
123
+ const servers = obj[key];
124
+ const out = {};
125
+ for (const [name, cfg] of Object.entries(servers)) {
126
+ if (isWrapped(cfg, interposer)) {
127
+ const a = cfg.args || [];
128
+ const urlIdx = a.indexOf('--url');
129
+ if (urlIdx >= 0) { // URL server (http_forward / sse_bridge)
130
+ const tIdx = a.indexOf('--transport');
131
+ const kind = tIdx >= 0 ? a[tIdx + 1] : 'http_forward';
132
+ const headers = {};
133
+ for (let j = 0; j < a.length - 1; j++) {
134
+ if (a[j] === '--header') {
135
+ const h = a[j + 1];
136
+ const c = h.indexOf(':');
137
+ if (c > 0)
138
+ headers[h.slice(0, c).trim()] = h.slice(c + 1).trim();
139
+ }
140
+ }
141
+ out[name] = {
142
+ type: kind === 'sse_bridge' ? 'sse' : 'http', url: a[urlIdx + 1],
143
+ ...(Object.keys(headers).length ? { headers } : {}),
144
+ ...(cfg.env ? { env: cfg.env } : {}),
145
+ };
146
+ }
147
+ else { // stdio server
148
+ const i = a.indexOf('--');
149
+ const realArgs = i >= 0 ? a.slice(i + 1) : [];
150
+ out[name] = { command: realArgs[0], ...(realArgs.length > 1 ? { args: realArgs.slice(1) } : {}), ...(cfg.env ? { env: cfg.env } : {}) };
151
+ }
152
+ wrapped.push(name);
153
+ }
154
+ else {
155
+ out[name] = cfg;
156
+ }
157
+ }
158
+ return { obj: { ...obj, [key]: out }, wrapped, skipped };
159
+ }
160
+ const BACKUP = '.guardion.bak';
161
+ /** Protect a single config file (backup + rewrite). Best-effort; never throws. */
162
+ export function protectFile(app, file, dryRun = false, opts = {}) {
163
+ try {
164
+ if (!fs.existsSync(file))
165
+ return { app, path: file, wrapped: [], skipped: [], error: 'not found' };
166
+ const obj = JSON.parse(fs.readFileSync(file, 'utf8'));
167
+ const { obj: next, wrapped, skipped } = rewriteServers(obj, opts);
168
+ if (wrapped.length && !dryRun) {
169
+ if (!fs.existsSync(file + BACKUP))
170
+ fs.copyFileSync(file, file + BACKUP);
171
+ fs.writeFileSync(file, JSON.stringify(next, null, 2) + '\n');
172
+ }
173
+ return { app, path: file, wrapped, skipped };
174
+ }
175
+ catch (e) {
176
+ return { app, path: file, wrapped: [], skipped: [], error: e.message };
177
+ }
178
+ }
179
+ /** Revert a single config file from its backup (or unwrap in place). */
180
+ export function revertFile(app, file) {
181
+ try {
182
+ if (fs.existsSync(file + BACKUP)) {
183
+ fs.copyFileSync(file + BACKUP, file);
184
+ fs.unlinkSync(file + BACKUP);
185
+ return { app, path: file, wrapped: ['(restored from backup)'], skipped: [] };
186
+ }
187
+ if (!fs.existsSync(file))
188
+ return { app, path: file, wrapped: [], skipped: [], error: 'not found' };
189
+ const obj = JSON.parse(fs.readFileSync(file, 'utf8'));
190
+ const { obj: next, wrapped } = unwrapServers(obj);
191
+ if (wrapped.length)
192
+ fs.writeFileSync(file, JSON.stringify(next, null, 2) + '\n');
193
+ return { app, path: file, wrapped, skipped: [] };
194
+ }
195
+ catch (e) {
196
+ return { app, path: file, wrapped: [], skipped: [], error: e.message };
197
+ }
198
+ }
199
+ /** Protect (or --revert) every discovered agent-app MCP config. */
200
+ export function protectAll(opts = {}) {
201
+ return knownAppConfigs()
202
+ .filter((c) => fs.existsSync(c.path))
203
+ .map((c) => (opts.revert ? revertFile(c.app, c.path) : protectFile(c.app, c.path, opts.dryRun, opts)));
204
+ }
205
+ //# sourceMappingURL=mcp-protect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-protect.js","sourceRoot":"","sources":["../../core/mcp-protect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import { type ScannedTool } from './inventory.js';
2
+ export interface McpServerConfig {
3
+ type?: string;
4
+ command?: string;
5
+ args?: string[];
6
+ env?: Record<string, string>;
7
+ url?: string;
8
+ headers?: Record<string, string>;
9
+ }
10
+ interface McpTool {
11
+ name: string;
12
+ description?: string;
13
+ inputSchema?: any;
14
+ }
15
+ /** Read configured MCP servers (name → raw config) from settings.json / .mcp.json. */
16
+ export declare function discoverMcpServers(cwd: string): Record<string, McpServerConfig>;
17
+ /** JSON-Schema inputSchema → our {name,type,description} param list (for schema_hash). */
18
+ export declare function inputSchemaToParams(schema: any): Array<{
19
+ name: string;
20
+ type?: string;
21
+ description?: string;
22
+ }>;
23
+ /** stdio MCP client: spawn the server, handshake, tools/list. Never throws. */
24
+ export declare function fetchToolsStdio(cfg: McpServerConfig, timeoutMs?: number): Promise<McpTool[]>;
25
+ /** http (Streamable HTTP) MCP client — best-effort JSON; handles SSE-wrapped replies. */
26
+ export declare function fetchToolsHttp(cfg: McpServerConfig, timeoutMs?: number): Promise<McpTool[]>;
27
+ export interface McpScanResult {
28
+ server: string;
29
+ tools: ScannedTool[];
30
+ error?: string;
31
+ }
32
+ /** Connect to every configured MCP server and collect its live tools as ScannedTool[]. */
33
+ export declare function mcpScan(cwd: string, timeoutMs?: number): Promise<McpScanResult[]>;
34
+ /** Fingerprint+pin (P1) and submit the live tools to Guard for poisoning/rug-pull. */
35
+ export declare function submitMcpScan(apiUrl: string, token: string, results: McpScanResult[], policy?: string, application?: string): Promise<{
36
+ status: number;
37
+ count: number;
38
+ }>;
39
+ export {};
40
+ //# sourceMappingURL=mcp-scan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-scan.d.ts","sourceRoot":"","sources":["../../core/mcp-scan.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,KAAK,WAAW,EAAiC,MAAM,gBAAgB,CAAC;AAEjF,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,UAAU,OAAO;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,GAAG,CAAA;CAAE;AAE3E,sFAAsF;AACtF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAmB/E;AAED,0FAA0F;AAC1F,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,GAAG,GAAG,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAO7G;AASD,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,GAAG,EAAE,eAAe,EAAE,SAAS,SAAO,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAkC1F;AAED,yFAAyF;AACzF,wBAAgB,cAAc,CAAC,GAAG,EAAE,eAAe,EAAE,SAAS,SAAO,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CA0CzF;AAQD,MAAM,WAAW,aAAa;IAAG,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,WAAW,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE;AAEvF,0FAA0F;AAC1F,wBAAsB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,SAAO,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAiBrF;AAED,sFAAsF;AACtF,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAC7F,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAK5C"}