@auth51/mcp-proxy 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/policy.js ADDED
@@ -0,0 +1,139 @@
1
+ import { readFileSync } from "node:fs";
2
+ /**
3
+ * The default policy if none is supplied. It is deliberately conservative for the
4
+ * coding-agent use case: allow by default, but block the classes of action that
5
+ * caused the real-world incidents (prod data destruction, recursive deletes,
6
+ * credential exfiltration, unscoped privilege escalation).
7
+ */
8
+ export const DEFAULT_POLICY = {
9
+ version: "1",
10
+ default: "allow",
11
+ rules: [
12
+ {
13
+ id: "destructive-sql",
14
+ description: "Destructive SQL (DROP/TRUNCATE/DELETE-without-WHERE) requires explicit human approval.",
15
+ tool: "*",
16
+ denyArgsMatch: [
17
+ "(?i)\\bdrop\\s+(table|database|schema)\\b",
18
+ "(?i)\\btruncate\\s+table\\b",
19
+ "(?i)\\bdelete\\s+from\\b(?![\\s\\S]*\\bwhere\\b)",
20
+ ],
21
+ },
22
+ {
23
+ id: "recursive-delete",
24
+ description: "Recursive / forced filesystem deletion is blocked.",
25
+ tool: "*",
26
+ denyArgsMatch: ["\\brm\\s+-[a-z]*r[a-z]*f\\b", "\\brm\\s+-[a-z]*f[a-z]*r\\b"],
27
+ },
28
+ {
29
+ id: "destructive-tool-name",
30
+ description: "Tools whose name implies irreversible destruction are blocked by least-privilege default.",
31
+ toolMatch: "(?i)(drop|truncate|destroy|wipe|purge)_?(database|table|all|backups?)",
32
+ },
33
+ {
34
+ id: "secret-exfiltration",
35
+ description: "Reading well-known secret material is blocked.",
36
+ tool: "*",
37
+ denyArgsMatch: [
38
+ "(?i)/\\.aws/credentials",
39
+ "(?i)/\\.ssh/id_(rsa|ed25519)",
40
+ // .env optionally followed by a suffix (.local), but terminated by any
41
+ // non-alphanumeric (quote/slash/end) so it fires on JSON-embedded paths
42
+ // like "project/.env" without matching ".environment"/".envrc".
43
+ "(?i)\\.env([^a-z0-9]|$)",
44
+ ],
45
+ },
46
+ ],
47
+ };
48
+ function globToRegExp(glob) {
49
+ // Minimal glob: escape regex specials, then turn \* into .*
50
+ const escaped = glob.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
51
+ return new RegExp(`^${escaped}$`);
52
+ }
53
+ /**
54
+ * Compile a pattern that may carry a leading inline-flag group like `(?i)` or
55
+ * `(?is)`. JavaScript's RegExp does NOT support inline flags, so we translate
56
+ * them to real RegExp flags. Returns null on an invalid pattern.
57
+ */
58
+ function compileRegExp(pattern) {
59
+ try {
60
+ const m = pattern.match(/^\(\?([a-z]+)\)/);
61
+ if (m) {
62
+ const flags = m[1].replace(/[^gimsuy]/g, "");
63
+ return new RegExp(pattern.slice(m[0].length), flags);
64
+ }
65
+ return new RegExp(pattern);
66
+ }
67
+ catch {
68
+ return null;
69
+ }
70
+ }
71
+ function ruleMatchesTool(rule, tool) {
72
+ if (rule.toolMatch) {
73
+ const re = compileRegExp(rule.toolMatch);
74
+ if (re && re.test(tool))
75
+ return true;
76
+ }
77
+ if (rule.tool) {
78
+ return globToRegExp(rule.tool).test(tool);
79
+ }
80
+ // A rule with neither tool nor toolMatch applies to every tool.
81
+ return !rule.toolMatch;
82
+ }
83
+ function argsTrigger(rule, argsText) {
84
+ if (!rule.denyArgsMatch || rule.denyArgsMatch.length === 0)
85
+ return true; // no arg constraint → fires on tool match alone
86
+ for (const pat of rule.denyArgsMatch) {
87
+ const re = compileRegExp(pat);
88
+ if (re && re.test(argsText))
89
+ return true;
90
+ }
91
+ return false;
92
+ }
93
+ export class PolicyEngine {
94
+ policy;
95
+ constructor(policy) {
96
+ this.policy = policy;
97
+ }
98
+ static load(path) {
99
+ if (!path)
100
+ return new PolicyEngine(DEFAULT_POLICY);
101
+ try {
102
+ const raw = readFileSync(path, "utf8");
103
+ const parsed = JSON.parse(raw);
104
+ if (!parsed.rules || !parsed.default || !parsed.version) {
105
+ throw new Error("policy missing required fields (version, default, rules)");
106
+ }
107
+ return new PolicyEngine(parsed);
108
+ }
109
+ catch (err) {
110
+ throw new Error(`auth51: failed to load policy from ${path}: ${err.message}`);
111
+ }
112
+ }
113
+ evaluate(call) {
114
+ for (const rule of this.policy.rules) {
115
+ if (!ruleMatchesTool(rule, call.tool))
116
+ continue;
117
+ const hasArgConstraint = !!rule.denyArgsMatch && rule.denyArgsMatch.length > 0;
118
+ const fires = hasArgConstraint ? argsTrigger(rule, call.argsText) : true;
119
+ if (!fires)
120
+ continue;
121
+ const action = rule.action ?? "deny";
122
+ // An explicit allow-rule short-circuits to allow.
123
+ if (action === "allow") {
124
+ return { allow: true, ruleId: rule.id, reason: rule.reason ?? rule.description ?? "allowed by policy rule" };
125
+ }
126
+ return {
127
+ allow: false,
128
+ ruleId: rule.id,
129
+ reason: rule.reason ?? rule.description ?? `blocked by policy rule "${rule.id}"`,
130
+ };
131
+ }
132
+ return {
133
+ allow: this.policy.default === "allow",
134
+ ruleId: "default",
135
+ reason: `no rule matched; policy default is "${this.policy.default}"`,
136
+ };
137
+ }
138
+ }
139
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAGvC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GAAW;IACpC,OAAO,EAAE,GAAG;IACZ,OAAO,EAAE,OAAO;IAChB,KAAK,EAAE;QACL;YACE,EAAE,EAAE,iBAAiB;YACrB,WAAW,EACT,wFAAwF;YAC1F,IAAI,EAAE,GAAG;YACT,aAAa,EAAE;gBACb,2CAA2C;gBAC3C,6BAA6B;gBAC7B,kDAAkD;aACnD;SACF;QACD;YACE,EAAE,EAAE,kBAAkB;YACtB,WAAW,EAAE,oDAAoD;YACjE,IAAI,EAAE,GAAG;YACT,aAAa,EAAE,CAAC,6BAA6B,EAAE,6BAA6B,CAAC;SAC9E;QACD;YACE,EAAE,EAAE,uBAAuB;YAC3B,WAAW,EACT,2FAA2F;YAC7F,SAAS,EAAE,uEAAuE;SACnF;QACD;YACE,EAAE,EAAE,qBAAqB;YACzB,WAAW,EAAE,gDAAgD;YAC7D,IAAI,EAAE,GAAG;YACT,aAAa,EAAE;gBACb,yBAAyB;gBACzB,8BAA8B;gBAC9B,uEAAuE;gBACvE,wEAAwE;gBACxE,gEAAgE;gBAChE,yBAAyB;aAC1B;SACF;KACF;CACF,CAAC;AAEF,SAAS,YAAY,CAAC,IAAY;IAChC,4DAA4D;IAC5D,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC/E,OAAO,IAAI,MAAM,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC;AACpC,CAAC;AAED;;;;GAIG;AACH,SAAS,aAAa,CAAC,OAAe;IACpC,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAC3C,IAAI,CAAC,EAAE,CAAC;YACN,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;YAC7C,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,CAAC;QACvD,CAAC;QACD,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,IAAgB,EAAE,IAAY;IACrD,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,MAAM,EAAE,GAAG,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACzC,IAAI,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;IACvC,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,OAAO,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5C,CAAC;IACD,gEAAgE;IAChE,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC;AACzB,CAAC;AAED,SAAS,WAAW,CAAC,IAAgB,EAAE,QAAgB;IACrD,IAAI,CAAC,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC,CAAC,gDAAgD;IACzH,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QACrC,MAAM,EAAE,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAC;IAC3C,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,OAAO,YAAY;IACf,MAAM,CAAS;IAEvB,YAAY,MAAc;QACxB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,IAAa;QACvB,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,YAAY,CAAC,cAAc,CAAC,CAAC;QACnD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACvC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAW,CAAC;YACzC,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACxD,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;YAC9E,CAAC;YACD,OAAO,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;QAClC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,sCAAsC,IAAI,KAAM,GAAa,CAAC,OAAO,EAAE,CACxE,CAAC;QACJ,CAAC;IACH,CAAC;IAED,QAAQ,CAAC,IAAc;QACrB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YACrC,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC;gBAAE,SAAS;YAEhD,MAAM,gBAAgB,GAAG,CAAC,CAAC,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC;YAC/E,MAAM,KAAK,GAAG,gBAAgB,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YACzE,IAAI,CAAC,KAAK;gBAAE,SAAS;YAErB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC;YACrC,kDAAkD;YAClD,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;gBACvB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,WAAW,IAAI,wBAAwB,EAAE,CAAC;YAC/G,CAAC;YACD,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,MAAM,EAAE,IAAI,CAAC,EAAE;gBACf,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,WAAW,IAAI,2BAA2B,IAAI,CAAC,EAAE,GAAG;aACjF,CAAC;QACJ,CAAC;QACD,OAAO;YACL,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,KAAK,OAAO;YACtC,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,uCAAuC,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG;SACtE,CAAC;IACJ,CAAC;CACF"}
package/dist/pop.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ interface EcJwk {
2
+ kty: string;
3
+ crv: string;
4
+ x: string;
5
+ y: string;
6
+ }
7
+ /** The proxy's DPoP key thumbprint (cnf.jkt) — request the Hop-B token bound to it. */
8
+ export declare function jkt(): string;
9
+ /** The public JWK (for tests / introspection). */
10
+ export declare function publicJwk(): EcJwk;
11
+ /**
12
+ * A DPoP proof JWT bound to this request (htm/htu), fresh (iat/jti), and — when
13
+ * a `token` is given — to that access token (ath). Signed ES256 with the proxy's
14
+ * key; header carries the public jwk (typ "dpop+jwt").
15
+ */
16
+ export declare function proof(htm: string, htu: string, opts?: {
17
+ token?: string;
18
+ }): string;
19
+ /** Reset the process key (tests only). */
20
+ export declare function _resetForTest(): void;
21
+ export {};
package/dist/pop.js ADDED
@@ -0,0 +1,76 @@
1
+ /**
2
+ * DPoP (RFC 9449) for the proxy's Hop-B downstream token — dependency-free via
3
+ * `node:crypto` (EC P-256 + ES256). The proxy holds one ephemeral key per
4
+ * process; the Hop-B RS token is bound to its thumbprint (`cnf.jkt`), and every
5
+ * server→RS request the proxy forwards carries a fresh proof. So a stolen RS
6
+ * token is inert without this key — the same sender-constraint the embed gives
7
+ * its downstream tokens, now on the proxy path.
8
+ */
9
+ import * as crypto from "node:crypto";
10
+ let _priv = null;
11
+ let _pubJwk = null;
12
+ let _jkt = null;
13
+ function b64u(buf) {
14
+ return buf.toString("base64url");
15
+ }
16
+ function ensureKey() {
17
+ if (_priv)
18
+ return;
19
+ const { publicKey, privateKey } = crypto.generateKeyPairSync("ec", {
20
+ namedCurve: "P-256",
21
+ });
22
+ _priv = privateKey;
23
+ const jwk = publicKey.export({ format: "jwk" });
24
+ _pubJwk = { kty: jwk.kty, crv: jwk.crv, x: jwk.x, y: jwk.y };
25
+ // RFC 7638 thumbprint: SHA-256 of the canonical JWK (members crv,kty,x,y in
26
+ // lexicographic order, no whitespace). Matches the verifier's _ec_jwk_thumbprint.
27
+ const canon = JSON.stringify({
28
+ crv: _pubJwk.crv, kty: _pubJwk.kty, x: _pubJwk.x, y: _pubJwk.y,
29
+ });
30
+ _jkt = b64u(crypto.createHash("sha256").update(canon).digest());
31
+ }
32
+ /** The proxy's DPoP key thumbprint (cnf.jkt) — request the Hop-B token bound to it. */
33
+ export function jkt() {
34
+ ensureKey();
35
+ return _jkt;
36
+ }
37
+ /** The public JWK (for tests / introspection). */
38
+ export function publicJwk() {
39
+ ensureKey();
40
+ return { ..._pubJwk };
41
+ }
42
+ /**
43
+ * A DPoP proof JWT bound to this request (htm/htu), fresh (iat/jti), and — when
44
+ * a `token` is given — to that access token (ath). Signed ES256 with the proxy's
45
+ * key; header carries the public jwk (typ "dpop+jwt").
46
+ */
47
+ export function proof(htm, htu, opts) {
48
+ ensureKey();
49
+ const header = { typ: "dpop+jwt", alg: "ES256", jwk: _pubJwk };
50
+ const now = Math.floor(Date.now() / 1000);
51
+ const payload = {
52
+ htm: htm.toUpperCase(),
53
+ htu,
54
+ iat: now,
55
+ jti: crypto.randomUUID(),
56
+ };
57
+ if (opts?.token) {
58
+ payload.ath = b64u(crypto.createHash("sha256").update(opts.token).digest());
59
+ }
60
+ const signingInput = b64u(Buffer.from(JSON.stringify(header))) +
61
+ "." +
62
+ b64u(Buffer.from(JSON.stringify(payload)));
63
+ // JOSE requires the raw (r||s) signature, not DER — dsaEncoding ieee-p1363.
64
+ const sig = crypto.sign("sha256", Buffer.from(signingInput), {
65
+ key: _priv,
66
+ dsaEncoding: "ieee-p1363",
67
+ });
68
+ return signingInput + "." + b64u(sig);
69
+ }
70
+ /** Reset the process key (tests only). */
71
+ export function _resetForTest() {
72
+ _priv = null;
73
+ _pubJwk = null;
74
+ _jkt = null;
75
+ }
76
+ //# sourceMappingURL=pop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pop.js","sourceRoot":"","sources":["../src/pop.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { ProxyOptions } from "./types.js";
2
+ /**
3
+ * Reduce a canonical scope to the tool name it governs — the segment after the
4
+ * last colon. e.g. "mcp:tool:github:read_repo" → "read_repo",
5
+ * "mcp:tool:read_repo" → "read_repo". The granted surface is matched against the
6
+ * MCP tool name, which we assume equals that last segment.
7
+ */
8
+ export declare function scopeToToolName(scope: string): string;
9
+ export declare function startProxy(opts: ProxyOptions): void;
package/dist/proxy.js ADDED
@@ -0,0 +1,337 @@
1
+ import { spawn } from "node:child_process";
2
+ import { randomUUID } from "node:crypto";
3
+ import { PolicyEngine } from "./policy.js";
4
+ import { Auditor, nowIso } from "./audit.js";
5
+ import { AuthorityClient } from "./authority.js";
6
+ import { IntegrityTracker } from "./integrity.js";
7
+ import { injectIntentMeta, extractIntent } from "./meta.js";
8
+ import { createEgressServer, setInFlightIntent } from "./egress.js";
9
+ /**
10
+ * Reduce a canonical scope to the tool name it governs — the segment after the
11
+ * last colon. e.g. "mcp:tool:github:read_repo" → "read_repo",
12
+ * "mcp:tool:read_repo" → "read_repo". The granted surface is matched against the
13
+ * MCP tool name, which we assume equals that last segment.
14
+ */
15
+ export function scopeToToolName(scope) {
16
+ const i = scope.lastIndexOf(":");
17
+ return i >= 0 ? scope.slice(i + 1) : scope;
18
+ }
19
+ /** The `params._meta` object of a JSON-RPC line, if any (for the egress bridge). */
20
+ function readIncomingMeta(line) {
21
+ try {
22
+ const msg = JSON.parse(line);
23
+ const m = msg?.params?._meta;
24
+ return m && typeof m === "object" ? m : undefined;
25
+ }
26
+ catch {
27
+ return undefined;
28
+ }
29
+ }
30
+ /** Read newline-delimited messages from a stream (MCP stdio framing). */
31
+ function onLines(stream, handler) {
32
+ let buf = "";
33
+ stream.on("data", (chunk) => {
34
+ buf += chunk.toString("utf8");
35
+ let idx;
36
+ while ((idx = buf.indexOf("\n")) >= 0) {
37
+ const line = buf.slice(0, idx);
38
+ buf = buf.slice(idx + 1);
39
+ if (line.trim().length > 0)
40
+ handler(line);
41
+ }
42
+ });
43
+ stream.on("end", () => {
44
+ if (buf.trim().length > 0)
45
+ handler(buf);
46
+ });
47
+ }
48
+ /**
49
+ * Build an MCP tools/call result that reports the block to the agent.
50
+ */
51
+ function denyResult(id, reason, ruleId) {
52
+ return (JSON.stringify({
53
+ jsonrpc: "2.0",
54
+ id: id ?? null,
55
+ result: {
56
+ content: [
57
+ {
58
+ type: "text",
59
+ text: `⛔ auth51 denied this action and did NOT forward it to the tool.\n` +
60
+ `Reason: ${reason}\n` +
61
+ `Policy rule: ${ruleId}\n\n` +
62
+ `This is a destructive or out-of-scope operation that requires explicit human approval. ` +
63
+ `Ask the user to confirm, or take a safer, reversible action instead.`,
64
+ },
65
+ ],
66
+ isError: true,
67
+ },
68
+ }) + "\n");
69
+ }
70
+ export function startProxy(opts) {
71
+ const policy = PolicyEngine.load(opts.policyPath);
72
+ const auditor = new Auditor(opts.auditPath);
73
+ const authority = opts.authority ? new AuthorityClient(opts.authority) : null;
74
+ // Server→RS egress governance (Hop-B). When configured (and an authority
75
+ // exists), start the reverse-proxy the MCP server's governed RS calls route
76
+ // through; each is exchanged for an RS-scoped token (DESIGN-proxy-egress-hop-b).
77
+ let egress = null;
78
+ if (authority && opts.egress) {
79
+ egress = createEgressServer(authority, {
80
+ rsId: opts.egress.rsId,
81
+ audience: opts.egress.audience,
82
+ targetBaseUrl: opts.egress.targetBaseUrl,
83
+ popEnabled: opts.egress.popEnabled,
84
+ }, (rec) => auditor.record({ ts: nowIso(), kind: "egress", ...rec }));
85
+ egress.server.listen(opts.egress.port ?? 0, "127.0.0.1", () => {
86
+ process.stderr.write(`[auth51] egress governing ${opts.egress.rsId} → ${opts.egress.targetBaseUrl} ` +
87
+ `on http://127.0.0.1:${egress.port()} (point the server's RS base URL here)\n`);
88
+ });
89
+ process.on("exit", () => void egress?.close());
90
+ }
91
+ // Slice 2d — the capability grant. Seed from the static CLI allowlist (Slice
92
+ // 1d), then refine from the authority's per-agent grant when available. A
93
+ // static allowlist enforces; the authority grant honours its own observe/
94
+ // enforce mode (observe-then-enforce rollout). Fetch is async + fail-open: a
95
+ // tools/list that races the fetch shows the full surface once (the authority's
96
+ // mint-time enforcement still blocks out-of-grant calls regardless).
97
+ const grantState = {
98
+ tools: opts.grant && opts.grant.length > 0 ? new Set(opts.grant) : null,
99
+ mode: "enforce",
100
+ source: "static",
101
+ };
102
+ if (authority && opts.authority?.appId && opts.authority?.agentId) {
103
+ void authority.fetchGrant().then((g) => {
104
+ if (!g)
105
+ return;
106
+ grantState.tools = new Set([...g.allowedScopes, ...g.stepUpScopes].map(scopeToToolName));
107
+ grantState.mode = g.mode;
108
+ grantState.source = `authority:v${g.version}`;
109
+ process.stderr.write(`[auth51] grant loaded (${grantState.source}, mode=${g.mode}): ` +
110
+ `${grantState.tools.size} tool(s) granted\n`);
111
+ });
112
+ }
113
+ // Integrity baseline lives alongside the audit log.
114
+ const integrityPath = opts.auditPath.replace(/[^/\\]*$/, "integrity-baseline.json");
115
+ const integrity = new IntegrityTracker(integrityPath);
116
+ // tools/list request ids awaiting a response we should inspect/filter.
117
+ const pendingToolsList = new Set();
118
+ process.stderr.write(`[auth51] guarding MCP server "${opts.serverLabel}" → ${opts.command} ${opts.commandArgs.join(" ")}\n` +
119
+ `[auth51] policy: ${opts.policyPath ?? "(built-in default)"} | audit: ${opts.auditPath}` +
120
+ (authority ? ` | authority: ${opts.authority.baseUrl}` : " | authority: (local only)") +
121
+ `\n`);
122
+ // Workflow seams (Slice 1e): one session per connection; a tamper-evident
123
+ // hash chain of intent-token jtis; a monotonic call index. Calls are assumed
124
+ // sequential (the agent waits for each tool result) — fine for v0; concurrent
125
+ // in-flight calls would need per-seq chaining instead of a single prevJti.
126
+ const sessionId = randomUUID();
127
+ let prevJti;
128
+ let seq = 0;
129
+ // L1 integrity: record/compare the launched-artifact fingerprint at startup.
130
+ const artifactDrift = integrity.checkArtifact(opts.serverLabel, opts.command, opts.commandArgs);
131
+ if (artifactDrift) {
132
+ process.stderr.write(`[auth51] INTEGRITY DRIFT: server artifact for "${opts.serverLabel}" changed since last run\n`);
133
+ auditor.record({
134
+ ts: nowIso(),
135
+ tool: "(integrity)",
136
+ args: { server: opts.serverLabel },
137
+ decision: "EVENT",
138
+ event: "INTEGRITY_DRIFT",
139
+ drift: [artifactDrift],
140
+ ruleId: "integrity-artifact",
141
+ reason: "launched-artifact fingerprint changed since last run",
142
+ sessionId,
143
+ });
144
+ }
145
+ const child = spawn(opts.command, opts.commandArgs, {
146
+ stdio: ["pipe", "pipe", "inherit"],
147
+ });
148
+ child.on("error", (err) => {
149
+ process.stderr.write(`[auth51] failed to start upstream MCP server: ${err.message}\n`);
150
+ process.exit(127);
151
+ });
152
+ child.on("exit", (code, signal) => {
153
+ process.exit(code ?? (signal ? 1 : 0));
154
+ });
155
+ // agent → proxy → (policy) → upstream
156
+ onLines(process.stdin, (line) => {
157
+ let msg = null;
158
+ try {
159
+ msg = JSON.parse(line);
160
+ }
161
+ catch {
162
+ // Not JSON we understand — stay transparent, forward as-is.
163
+ child.stdin.write(line + "\n");
164
+ return;
165
+ }
166
+ // Track tools/list requests so we can inspect (integrity) + filter (grant)
167
+ // the matching response coming back from the server.
168
+ if (msg.method === "tools/list" && msg.id != null) {
169
+ pendingToolsList.add(msg.id);
170
+ }
171
+ if (msg.method !== "tools/call" || !msg.params) {
172
+ child.stdin.write(line + "\n");
173
+ return;
174
+ }
175
+ const tool = String(msg.params.name ?? "");
176
+ const args = msg.params.arguments ?? {};
177
+ let argsText = "";
178
+ try {
179
+ argsText = JSON.stringify(args);
180
+ }
181
+ catch {
182
+ argsText = String(args);
183
+ }
184
+ const call = { tool, args, argsText };
185
+ const callSeq = ++seq;
186
+ // At Slice 1, declared-intent == observed-call (no separate intent source yet);
187
+ // the seam exists so the divergence signal can be computed once app-attested
188
+ // or richer intent arrives (§4.2).
189
+ const declaredIntent = { tool, args, provenance: "llm-declared" };
190
+ const observedCall = { tool, args };
191
+ let decision = policy.evaluate(call);
192
+ // Grant check (Slice 2d): a tool outside the capability grant is denied,
193
+ // independent of the declarative policy. In observe mode we log the would-be
194
+ // denial but let the call through (observe-then-enforce, DESIGN §2.3).
195
+ if (grantState.tools && !grantState.tools.has(tool)) {
196
+ if (grantState.mode === "enforce") {
197
+ decision = {
198
+ allow: false,
199
+ ruleId: "grant",
200
+ reason: `tool "${tool}" is not in this agent's capability grant (${grantState.source})`,
201
+ };
202
+ }
203
+ else {
204
+ process.stderr.write(`[auth51] grant[observe] ${tool} is out-of-grant (${grantState.source}) — would deny in enforce\n`);
205
+ }
206
+ }
207
+ if (!decision.allow) {
208
+ auditor.record({
209
+ ts: nowIso(),
210
+ tool,
211
+ args,
212
+ decision: "DENY",
213
+ ruleId: decision.ruleId,
214
+ reason: decision.reason,
215
+ agent: opts.agent,
216
+ sessionId,
217
+ seq: callSeq,
218
+ prevJti,
219
+ declaredIntent,
220
+ observedCall,
221
+ });
222
+ process.stderr.write(`[auth51] DENY ${tool} — ${decision.reason} (rule: ${decision.ruleId})\n`);
223
+ process.stdout.write(denyResult(msg.id, decision.reason, decision.ruleId));
224
+ return;
225
+ }
226
+ // ALLOW. When an authority is configured, mint the intent token and ride it
227
+ // INSIDE the JSON-RPC call under _meta ("io.auth51/intent") BEFORE
228
+ // forwarding — binding it to this exact tool + args and carrying it to the
229
+ // server (Hop A). Without an authority we forward unchanged (local policy is
230
+ // still enforced); a mint failure is fail-open (forward unchanged). The mint
231
+ // round-trip runs off the reader via this async task, and per-call ordering
232
+ // (mint → inject → forward) is preserved.
233
+ void (async () => {
234
+ const chainedFrom = prevJti; // the token this step links to
235
+ const chain = { session_id: sessionId, prev_jti: chainedFrom, seq: callSeq };
236
+ let intentJti;
237
+ let outLine = line;
238
+ // Case E: a token an upstream embed already put in _meta.
239
+ let inFlightToken = extractIntent(readIncomingMeta(line));
240
+ if (authority) {
241
+ const minted = await authority.mintIntent({
242
+ scope: `mcp:tool:${tool}`,
243
+ workflowId: sessionId,
244
+ workflowStep: { action: tool, declared_intent: declaredIntent, seq: callSeq },
245
+ delegationContext: chain,
246
+ });
247
+ if (minted) {
248
+ intentJti = minted.jti;
249
+ prevJti = minted.jti; // extend the chain
250
+ // Hop A: the token now rides in the call's _meta to the server.
251
+ outLine = injectIntentMeta(line, minted.token, chain);
252
+ inFlightToken = minted.token; // what we actually forwarded in _meta
253
+ }
254
+ }
255
+ // Ingress→egress bridge (single-flight): record THIS tool call's intent
256
+ // token so the egress reverse-proxy can exchange it at the server→RS
257
+ // boundary (Hop B). Null ⇒ the egress mints its own (Case T). One in-flight
258
+ // call at a time for a stdio server, so a single slot is correct.
259
+ setInFlightIntent(inFlightToken);
260
+ child.stdin.write(outLine + "\n");
261
+ auditor.record({
262
+ ts: nowIso(),
263
+ tool,
264
+ args,
265
+ decision: "ALLOW",
266
+ ruleId: decision.ruleId,
267
+ reason: decision.reason,
268
+ agent: opts.agent,
269
+ intentJti,
270
+ sessionId,
271
+ seq: callSeq,
272
+ prevJti: chainedFrom,
273
+ declaredIntent,
274
+ observedCall,
275
+ });
276
+ })();
277
+ });
278
+ // upstream → proxy → agent. Pure passthrough EXCEPT tools/list responses,
279
+ // which we inspect (L0 integrity) and filter (capability grant).
280
+ onLines(child.stdout, (line) => {
281
+ let out = line;
282
+ try {
283
+ const msg = JSON.parse(line);
284
+ const id = msg.id;
285
+ if (id != null &&
286
+ pendingToolsList.has(id) &&
287
+ msg.result &&
288
+ Array.isArray(msg.result.tools)) {
289
+ pendingToolsList.delete(id);
290
+ const tools = msg.result.tools;
291
+ // 1c — L0 integrity: fingerprint + drift detection.
292
+ const drift = integrity.checkTools(opts.serverLabel, tools);
293
+ if (drift.length > 0) {
294
+ for (const d of drift) {
295
+ process.stderr.write(`[auth51] INTEGRITY DRIFT ${opts.serverLabel}/${d.tool}: ${d.kind}\n`);
296
+ }
297
+ auditor.record({
298
+ ts: nowIso(),
299
+ tool: "(integrity)",
300
+ args: { server: opts.serverLabel },
301
+ decision: "EVENT",
302
+ event: "INTEGRITY_DRIFT",
303
+ drift,
304
+ ruleId: "integrity-tools",
305
+ reason: `${drift.length} tool fingerprint change(s) on tools/list`,
306
+ sessionId,
307
+ });
308
+ }
309
+ // 2d — capability grant: filter the surface the agent's model can see.
310
+ // Enforce mode strips ungranted tools; observe mode logs what it *would*
311
+ // strip but leaves the surface intact (observe-then-enforce, §2.3).
312
+ if (grantState.tools) {
313
+ const granted = grantState.tools;
314
+ const kept = tools.filter((t) => granted.has(t.name));
315
+ if (kept.length !== tools.length) {
316
+ if (grantState.mode === "enforce") {
317
+ msg.result.tools = kept;
318
+ out = JSON.stringify(msg);
319
+ process.stderr.write(`[auth51] grant filter (${grantState.source}): exposing ${kept.length}/${tools.length} tools to the agent\n`);
320
+ }
321
+ else {
322
+ process.stderr.write(`[auth51] grant[observe] (${grantState.source}): would expose ${kept.length}/${tools.length} tools (not filtering)\n`);
323
+ }
324
+ }
325
+ }
326
+ }
327
+ }
328
+ catch {
329
+ /* not JSON / not a tools/list response → passthrough unchanged */
330
+ }
331
+ process.stdout.write(out + "\n");
332
+ });
333
+ process.stdin.on("end", () => {
334
+ child.stdin.end();
335
+ });
336
+ }
337
+ //# sourceMappingURL=proxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"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"}