@usetorii/gateway 0.0.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 (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +116 -0
  3. package/dist/audit/index.d.ts +5 -0
  4. package/dist/audit/index.d.ts.map +1 -0
  5. package/dist/audit/index.js +27 -0
  6. package/dist/audit/index.js.map +1 -0
  7. package/dist/core/config/loader.d.ts +8 -0
  8. package/dist/core/config/loader.d.ts.map +1 -0
  9. package/dist/core/config/loader.js +61 -0
  10. package/dist/core/config/loader.js.map +1 -0
  11. package/dist/core/config/schema.d.ts +541 -0
  12. package/dist/core/config/schema.d.ts.map +1 -0
  13. package/dist/core/config/schema.js +90 -0
  14. package/dist/core/config/schema.js.map +1 -0
  15. package/dist/core/index.d.ts +4 -0
  16. package/dist/core/index.d.ts.map +1 -0
  17. package/dist/core/index.js +3 -0
  18. package/dist/core/index.js.map +1 -0
  19. package/dist/core/types.d.ts +45 -0
  20. package/dist/core/types.d.ts.map +1 -0
  21. package/dist/core/types.js +2 -0
  22. package/dist/core/types.js.map +1 -0
  23. package/dist/index.d.ts +3 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +43 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/mux/index.d.ts +8 -0
  28. package/dist/mux/index.d.ts.map +1 -0
  29. package/dist/mux/index.js +120 -0
  30. package/dist/mux/index.js.map +1 -0
  31. package/dist/process/manager.d.ts +12 -0
  32. package/dist/process/manager.d.ts.map +1 -0
  33. package/dist/process/manager.js +79 -0
  34. package/dist/process/manager.js.map +1 -0
  35. package/dist/runners/stdio.d.ts +7 -0
  36. package/dist/runners/stdio.d.ts.map +1 -0
  37. package/dist/runners/stdio.js +63 -0
  38. package/dist/runners/stdio.js.map +1 -0
  39. package/dist/security/consent.d.ts +5 -0
  40. package/dist/security/consent.d.ts.map +1 -0
  41. package/dist/security/consent.js +49 -0
  42. package/dist/security/consent.js.map +1 -0
  43. package/dist/security/policy.d.ts +22 -0
  44. package/dist/security/policy.d.ts.map +1 -0
  45. package/dist/security/policy.js +114 -0
  46. package/dist/security/policy.js.map +1 -0
  47. package/dist/security/scanner.d.ts +39 -0
  48. package/dist/security/scanner.d.ts.map +1 -0
  49. package/dist/security/scanner.js +96 -0
  50. package/dist/security/scanner.js.map +1 -0
  51. package/package.json +46 -0
@@ -0,0 +1,45 @@
1
+ import type { z } from "zod";
2
+ import type { ToriiConfigSchema, ServerDefinitionSchema, ServerSourceSchema } from "./config/schema.js";
3
+ export type ToriiConfig = z.infer<typeof ToriiConfigSchema>;
4
+ export type ServerDefinition = z.infer<typeof ServerDefinitionSchema>;
5
+ export type ServerSource = z.infer<typeof ServerSourceSchema>;
6
+ export interface ConnectedServer {
7
+ id: string;
8
+ client: MuxClient;
9
+ }
10
+ export interface MuxClient {
11
+ listTools(): Promise<{
12
+ tools: MCPTool[];
13
+ }>;
14
+ callTool(params: {
15
+ name: string;
16
+ arguments?: Record<string, unknown>;
17
+ }): Promise<MCPToolResult>;
18
+ close(): Promise<void>;
19
+ }
20
+ export interface MCPTool {
21
+ name: string;
22
+ description?: string;
23
+ inputSchema?: Record<string, unknown>;
24
+ }
25
+ export type MCPToolResult = Record<string, unknown>;
26
+ export interface SecurityFinding {
27
+ id: string;
28
+ severity: string;
29
+ category: string;
30
+ description: string;
31
+ matched_text?: string;
32
+ }
33
+ export interface AuditEntry {
34
+ ts: string;
35
+ server: string;
36
+ tool: string;
37
+ args_size: number;
38
+ result_size: number;
39
+ duration_ms: number;
40
+ error?: string;
41
+ blocked?: boolean;
42
+ threat_level?: string;
43
+ security_findings?: SecurityFinding[];
44
+ }
45
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EACV,iBAAiB,EACjB,sBAAsB,EACtB,kBAAkB,EACnB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC5D,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AACtE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAG9D,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,SAAS,CAAC;CACnB;AAGD,MAAM,WAAW,SAAS;IACxB,SAAS,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC,CAAC;IAC3C,QAAQ,CAAC,MAAM,EAAE;QACf,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACrC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAC3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC;AAID,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAIpD,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,eAAe,EAAE,CAAC;CACvC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env node
2
+ import { loadConfig } from "./core/index.js";
3
+ import { startServers, stopServers } from "./process/manager.js";
4
+ import { createMux } from "./mux/index.js";
5
+ async function main() {
6
+ let servers = [];
7
+ // ── Graceful shutdown ─────────────────────────────────────────────────────
8
+ async function shutdown(signal) {
9
+ process.stderr.write(`\n[torii] received ${signal}, shutting down...\n`);
10
+ await stopServers(servers);
11
+ process.exit(0);
12
+ }
13
+ process.on("SIGTERM", () => shutdown("SIGTERM"));
14
+ process.on("SIGINT", () => shutdown("SIGINT"));
15
+ // ── Boot ──────────────────────────────────────────────────────────────────
16
+ let config;
17
+ try {
18
+ config = loadConfig();
19
+ }
20
+ catch (err) {
21
+ process.stderr.write(`[torii] config error: ${err.message}\n`);
22
+ process.exit(1);
23
+ }
24
+ process.stderr.write(`[torii] starting gateway with ${config.servers.filter((s) => s.enabled !== false).length} server(s)\n`);
25
+ try {
26
+ servers = await startServers(config);
27
+ }
28
+ catch (err) {
29
+ process.stderr.write(`[torii] startup failed: ${err.message}\n`);
30
+ process.exit(1);
31
+ }
32
+ // ── Run mux (blocks until the MCP connection closes) ─────────────────────
33
+ try {
34
+ await createMux(servers);
35
+ }
36
+ catch (err) {
37
+ process.stderr.write(`[torii] mux error: ${err.message}\n`);
38
+ await stopServers(servers);
39
+ process.exit(1);
40
+ }
41
+ }
42
+ main();
43
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAG3C,KAAK,UAAU,IAAI;IACjB,IAAI,OAAO,GAAsB,EAAE,CAAC;IAEpC,6EAA6E;IAC7E,KAAK,UAAU,QAAQ,CAAC,MAAc;QACpC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sBAAsB,MAAM,sBAAsB,CAAC,CAAC;QACzE,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC;QAC3B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;IACjD,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IAE/C,6EAA6E;IAC7E,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,MAAM,GAAG,UAAU,EAAE,CAAC;IACxB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yBAA0B,GAAa,CAAC,OAAO,IAAI,CAAC,CAAC;QAC1E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,iCAAiC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,KAAK,CAAC,CAAC,MAAM,cAAc,CACxG,CAAC;IAEF,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,2BAA4B,GAAa,CAAC,OAAO,IAAI,CAAC,CAAC;QAC5E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,4EAA4E;IAC5E,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sBAAuB,GAAa,CAAC,OAAO,IAAI,CAAC,CAAC;QACvE,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC;QAC3B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { ConnectedServer } from "../core/index.js";
2
+ export declare function buildPrefixedName(serverId: string, toolName: string): string;
3
+ export declare function parsePrefixedName(prefixedName: string): {
4
+ serverId: string;
5
+ toolName: string;
6
+ } | null;
7
+ export declare function createMux(servers: ConnectedServer[]): Promise<void>;
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mux/index.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAQxD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE5E;AAED,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,GACnB;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAO/C;AAED,wBAAsB,SAAS,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuHzE"}
@@ -0,0 +1,120 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { ListToolsRequestSchema, CallToolRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
4
+ import { logCall, makeEntry } from "../audit/index.js";
5
+ import { scanToolResult } from "../security/scanner.js";
6
+ import { isHighRisk, requestConsent } from "../security/consent.js";
7
+ import { evaluatePolicy } from "../security/policy.js";
8
+ const SEP = "__";
9
+ export function buildPrefixedName(serverId, toolName) {
10
+ return `${serverId}${SEP}${toolName}`;
11
+ }
12
+ export function parsePrefixedName(prefixedName) {
13
+ const idx = prefixedName.indexOf(SEP);
14
+ if (idx === -1)
15
+ return null;
16
+ return {
17
+ serverId: prefixedName.slice(0, idx),
18
+ toolName: prefixedName.slice(idx + SEP.length),
19
+ };
20
+ }
21
+ export async function createMux(servers) {
22
+ const serverMap = new Map(servers.map((s) => [s.id, s.client]));
23
+ const mux = new Server({ name: "torii", version: "0.1.0" }, { capabilities: { tools: {} } });
24
+ mux.setRequestHandler(ListToolsRequestSchema, async () => {
25
+ const results = await Promise.allSettled(servers.map(async ({ id, client }) => {
26
+ const { tools } = await client.listTools();
27
+ return tools.map((tool) => ({
28
+ ...tool,
29
+ name: buildPrefixedName(id, tool.name),
30
+ description: tool.description ? `[${id}] ${tool.description}` : `[${id}]`,
31
+ }));
32
+ }));
33
+ return { tools: results.flatMap((r) => (r.status === "fulfilled" ? r.value : [])) };
34
+ });
35
+ mux.setRequestHandler(CallToolRequestSchema, async (request) => {
36
+ const { name, arguments: args } = request.params;
37
+ const parsed = parsePrefixedName(name);
38
+ if (!parsed)
39
+ throw new Error(`Invalid tool name '${name}'. Expected format: serverId__toolName`);
40
+ const { serverId, toolName } = parsed;
41
+ const client = serverMap.get(serverId);
42
+ if (!client)
43
+ throw new Error(`Unknown server '${serverId}'. Available: ${[...serverMap.keys()].join(", ")}`);
44
+ const startedAt = Date.now();
45
+ let result;
46
+ let scan = null;
47
+ try {
48
+ // ── Policy gate (Layer 4 — declarative rules) ──────────────────────
49
+ const matchedPolicy = evaluatePolicy(serverId, toolName, args);
50
+ if (matchedPolicy) {
51
+ const policyMsg = matchedPolicy.reason
52
+ ? `Policy '${matchedPolicy.name}': ${matchedPolicy.reason}`
53
+ : `Blocked by policy '${matchedPolicy.name}'`;
54
+ if (matchedPolicy.action === "deny") {
55
+ logCall(makeEntry(serverId, toolName, args, null, startedAt, policyMsg, true, "high", []));
56
+ throw new Error(`Tool '${serverId}__${toolName}' blocked. ${policyMsg}`);
57
+ }
58
+ // require_consent — fall through to consent gate regardless of HIGH_RISK pattern
59
+ if (matchedPolicy.action === "require_consent") {
60
+ const decision = await requestConsent(serverId, toolName, args);
61
+ if (decision === "rejected") {
62
+ const msg = `'${serverId}__${toolName}' rejected by user (policy: ${matchedPolicy.name})`;
63
+ logCall(makeEntry(serverId, toolName, args, null, startedAt, msg, true, "high", []));
64
+ throw new Error(msg);
65
+ }
66
+ if (decision === "timeout") {
67
+ const msg = `'${serverId}__${toolName}' consent timed out (policy: ${matchedPolicy.name})`;
68
+ logCall(makeEntry(serverId, toolName, args, null, startedAt, msg, true, "medium", []));
69
+ throw new Error(msg);
70
+ }
71
+ // approved or skipped → proceed
72
+ }
73
+ }
74
+ // ── Consent gate (Layer 5 — human-in-the-loop for high-risk tools) ─
75
+ if (!matchedPolicy && isHighRisk(toolName)) {
76
+ const decision = await requestConsent(serverId, toolName, args);
77
+ if (decision === "rejected") {
78
+ const msg = `'${serverId}__${toolName}' was rejected by the user`;
79
+ logCall(makeEntry(serverId, toolName, args, null, startedAt, msg, true, "high", []));
80
+ throw new Error(msg);
81
+ }
82
+ if (decision === "timeout") {
83
+ const msg = `'${serverId}__${toolName}' consent request timed out — action blocked`;
84
+ logCall(makeEntry(serverId, toolName, args, null, startedAt, msg, true, "medium", []));
85
+ throw new Error(msg);
86
+ }
87
+ // "approved" or "skipped" → proceed
88
+ }
89
+ result = await client.callTool({ name: toolName, arguments: args });
90
+ // ── Tool-response scan ────────────────────────────────────────────
91
+ // The gateway posts the tool result to the Torii backend, which decides
92
+ // verdicts. If TORII_API_KEY isn't set, or the endpoint isn't deployed
93
+ // yet, or the network fails, the scan is a no-op (graceful degrade).
94
+ scan = await scanToolResult(serverId, toolName, result);
95
+ if (scan?.blocked) {
96
+ const ids = scan.findings.map((f) => f.id).join(", ");
97
+ const errMsg = `Tool result from '${serverId}__${toolName}' blocked by security scanner ` +
98
+ `[${scan.threat_level}]: ${ids}`;
99
+ logCall(makeEntry(serverId, toolName, args, null, startedAt, errMsg, true, scan.threat_level, scan.findings));
100
+ throw new Error(errMsg);
101
+ }
102
+ if (scan && !scan.safe) {
103
+ process.stderr.write(`[torii/security] ${serverId}__${toolName} flagged [${scan.threat_level}]: ` +
104
+ scan.findings.map((f) => f.id).join(", ") + "\n");
105
+ }
106
+ logCall(makeEntry(serverId, toolName, args, result, startedAt, undefined, false, scan?.threat_level, scan?.findings));
107
+ return result;
108
+ }
109
+ catch (err) {
110
+ if (!(err instanceof Error && err.message.includes("blocked by security scanner"))) {
111
+ logCall(makeEntry(serverId, toolName, args, null, startedAt, err));
112
+ }
113
+ throw err;
114
+ }
115
+ });
116
+ const transport = new StdioServerTransport();
117
+ await mux.connect(transport);
118
+ process.stderr.write("[torii] gateway ready\n");
119
+ }
120
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mux/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { ToriiConfig, ConnectedServer } from "../core/index.js";
2
+ /**
3
+ * Starts all enabled servers defined in the config and returns their
4
+ * connected handles. Failures on individual servers are logged and skipped
5
+ * so that a single broken server doesn't prevent the gateway from starting.
6
+ */
7
+ export declare function startServers(config: ToriiConfig): Promise<ConnectedServer[]>;
8
+ /**
9
+ * Gracefully closes all connected servers.
10
+ */
11
+ export declare function stopServers(servers: ConnectedServer[]): Promise<void>;
12
+ //# sourceMappingURL=manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/process/manager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AA6BrE;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CA2ClF;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAW3E"}
@@ -0,0 +1,79 @@
1
+ import { resolveEnv } from "../core/index.js";
2
+ import { spawnServer } from "../runners/stdio.js";
3
+ import { loadPolicies, startPolicyRefresh } from "../security/policy.js";
4
+ /**
5
+ * Fetches decrypted credentials for a server from the Torii Vault API.
6
+ * Returns empty object if TORII_API_URL / TORII_API_KEY are not set, or on
7
+ * any network error (graceful degradation — vault is optional).
8
+ */
9
+ async function fetchVaultSecrets(serverId) {
10
+ const apiUrl = process.env.TORII_API_URL;
11
+ const apiKey = process.env.TORII_API_KEY;
12
+ if (!apiUrl || !apiKey)
13
+ return {};
14
+ try {
15
+ const res = await fetch(`${apiUrl}/v1/vault/secrets/${encodeURIComponent(serverId)}`, {
16
+ headers: { "X-Torii-Key": apiKey },
17
+ signal: AbortSignal.timeout(3000),
18
+ });
19
+ if (!res.ok)
20
+ return {};
21
+ return (await res.json());
22
+ }
23
+ catch {
24
+ process.stderr.write(`[torii] warn: could not fetch vault secrets for '${serverId}' — continuing without them\n`);
25
+ return {};
26
+ }
27
+ }
28
+ /**
29
+ * Starts all enabled servers defined in the config and returns their
30
+ * connected handles. Failures on individual servers are logged and skipped
31
+ * so that a single broken server doesn't prevent the gateway from starting.
32
+ */
33
+ export async function startServers(config) {
34
+ // Load policies from API (non-blocking — failure is graceful)
35
+ await loadPolicies();
36
+ startPolicyRefresh();
37
+ const enabled = config.servers.filter((s) => s.enabled !== false);
38
+ if (enabled.length === 0) {
39
+ throw new Error("No enabled servers found in config. Set enabled: true on at least one server.");
40
+ }
41
+ const results = await Promise.allSettled(enabled.map(async (def) => {
42
+ process.stderr.write(`[torii] starting server '${def.id}'...\n`);
43
+ // Vault provides base credentials; config env block can override per-key
44
+ const vaultEnv = await fetchVaultSecrets(def.id);
45
+ const configEnv = resolveEnv(def.env ?? {});
46
+ const env = { ...vaultEnv, ...configEnv };
47
+ const client = await spawnServer(def, env);
48
+ process.stderr.write(`[torii] server '${def.id}' ready\n`);
49
+ return { id: def.id, client };
50
+ }));
51
+ const connected = [];
52
+ for (const result of results) {
53
+ if (result.status === "fulfilled") {
54
+ connected.push(result.value);
55
+ }
56
+ else {
57
+ process.stderr.write(`[torii] error: failed to start server — ${result.reason}\n`);
58
+ }
59
+ }
60
+ if (connected.length === 0) {
61
+ throw new Error("All servers failed to start. Check the errors above.");
62
+ }
63
+ return connected;
64
+ }
65
+ /**
66
+ * Gracefully closes all connected servers.
67
+ */
68
+ export async function stopServers(servers) {
69
+ await Promise.allSettled(servers.map(async ({ id, client }) => {
70
+ try {
71
+ await client.close();
72
+ process.stderr.write(`[torii] server '${id}' stopped\n`);
73
+ }
74
+ catch {
75
+ // Ignore close errors during shutdown
76
+ }
77
+ }));
78
+ }
79
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/process/manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { ServerDefinition, MuxClient } from "../core/index.js";
2
+ /**
3
+ * Spawns a server as a child process and connects to it via MCP stdio.
4
+ * Returns a MuxClient that the multiplexer can talk to.
5
+ */
6
+ export declare function spawnServer(def: ServerDefinition, resolvedEnv: Record<string, string>): Promise<MuxClient>;
7
+ //# sourceMappingURL=stdio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../src/runners/stdio.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAwCpE;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,gBAAgB,EACrB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAClC,OAAO,CAAC,SAAS,CAAC,CAgCpB"}
@@ -0,0 +1,63 @@
1
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2
+ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
3
+ /**
4
+ * Returns the shell command needed to start a server based on its source type.
5
+ * Currently handles npm and pypi. Docker/repo/remote runners are Phase 3.
6
+ */
7
+ function resolveCommand(def) {
8
+ const { source } = def;
9
+ switch (source.type) {
10
+ case "npm": {
11
+ const pkg = source.version
12
+ ? `${source.package}@${source.version}`
13
+ : source.package;
14
+ return { command: "npx", args: ["-y", pkg] };
15
+ }
16
+ case "pypi": {
17
+ const pkg = source.version
18
+ ? `${source.package}==${source.version}`
19
+ : source.package;
20
+ // uvx runs a PyPI tool in an isolated venv without a global install
21
+ return { command: "uvx", args: [pkg] };
22
+ }
23
+ case "local":
24
+ // Run a pre-built JS entry point directly with the current Node binary.
25
+ // Useful for monorepo development before packages are published to npm.
26
+ return { command: process.execPath, args: [source.path] };
27
+ case "docker":
28
+ case "repo":
29
+ case "remote":
30
+ throw new Error(`Runner for source type '${source.type}' is not implemented yet. ` +
31
+ `Only 'npm', 'pypi', and 'local' are supported in Phase 1.`);
32
+ }
33
+ }
34
+ /**
35
+ * Spawns a server as a child process and connects to it via MCP stdio.
36
+ * Returns a MuxClient that the multiplexer can talk to.
37
+ */
38
+ export async function spawnServer(def, resolvedEnv) {
39
+ const { command, args } = resolveCommand(def);
40
+ const transport = new StdioClientTransport({
41
+ command,
42
+ args,
43
+ env: {
44
+ ...process.env,
45
+ ...resolvedEnv,
46
+ },
47
+ });
48
+ const client = new Client({ name: "torii-gateway", version: "0.1.0" }, { capabilities: {} });
49
+ try {
50
+ await client.connect(transport);
51
+ }
52
+ catch (err) {
53
+ throw new Error(`Failed to connect to server '${def.id}' ` +
54
+ `(${command} ${args.join(" ")}): ${err.message}`);
55
+ }
56
+ // Wrap the SDK client in the MuxClient interface
57
+ return {
58
+ listTools: () => client.listTools(),
59
+ callTool: (params) => client.callTool(params),
60
+ close: () => client.close(),
61
+ };
62
+ }
63
+ //# sourceMappingURL=stdio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdio.js","sourceRoot":"","sources":["../../src/runners/stdio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAGjF;;;GAGG;AACH,SAAS,cAAc,CAAC,GAAqB;IAC3C,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;IAEvB,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,KAAK,CAAC,CAAC,CAAC;YACX,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO;gBACxB,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,EAAE;gBACvC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;YACnB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;QAC/C,CAAC;QAED,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO;gBACxB,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,KAAK,MAAM,CAAC,OAAO,EAAE;gBACxC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;YACnB,oEAAoE;YACpE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;QACzC,CAAC;QAED,KAAK,OAAO;YACV,wEAAwE;YACxE,wEAAwE;YACxE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QAE5D,KAAK,QAAQ,CAAC;QACd,KAAK,MAAM,CAAC;QACZ,KAAK,QAAQ;YACX,MAAM,IAAI,KAAK,CACb,2BAA2B,MAAM,CAAC,IAAI,4BAA4B;gBAChE,2DAA2D,CAC9D,CAAC;IACN,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,GAAqB,EACrB,WAAmC;IAEnC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IAE9C,MAAM,SAAS,GAAG,IAAI,oBAAoB,CAAC;QACzC,OAAO;QACP,IAAI;QACJ,GAAG,EAAE;YACH,GAAG,OAAO,CAAC,GAAG;YACd,GAAG,WAAW;SACW;KAC5B,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,OAAO,EAAE,EAC3C,EAAE,YAAY,EAAE,EAAE,EAAE,CACrB,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,gCAAgC,GAAG,CAAC,EAAE,IAAI;YACxC,IAAI,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAO,GAAa,CAAC,OAAO,EAAE,CAC9D,CAAC;IACJ,CAAC;IAED,iDAAiD;IACjD,OAAO;QACL,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE;QACnC,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAsC;QAClF,KAAK,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE;KAC5B,CAAC;AACJ,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function isHighRisk(toolName: string): boolean;
2
+ type Decision = "approved" | "rejected" | "timeout" | "skipped";
3
+ export declare function requestConsent(serverId: string, toolName: string, args: unknown): Promise<Decision>;
4
+ export {};
5
+ //# sourceMappingURL=consent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consent.d.ts","sourceRoot":"","sources":["../../src/security/consent.ts"],"names":[],"mappings":"AAWA,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEpD;AAID,KAAK,QAAQ,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;AAEhE,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,GACZ,OAAO,CAAC,QAAQ,CAAC,CA4CnB"}
@@ -0,0 +1,49 @@
1
+ // ── High-risk tool patterns ────────────────────────────────────────────────
2
+ // These trigger a consent request before the tool executes.
3
+ const HIGH_RISK = [
4
+ /\b(delete|destroy|drop|purge|wipe|remove)\b/i,
5
+ /\b(deploy|release|publish|push_to)\b/i,
6
+ /\b(execute|eval|run_command|shell|exec)\b/i,
7
+ /\b(send_email|send_message|notify|alert)\b/i,
8
+ /\b(transfer|pay|charge|refund|cancel)\b/i,
9
+ ];
10
+ export function isHighRisk(toolName) {
11
+ return HIGH_RISK.some((p) => p.test(toolName));
12
+ }
13
+ export async function requestConsent(serverId, toolName, args) {
14
+ const apiUrl = process.env.TORII_API_URL;
15
+ const apiKey = process.env.TORII_API_KEY;
16
+ // If gateway not connected to API, fail open (allow)
17
+ if (!apiUrl || !apiKey)
18
+ return "skipped";
19
+ try {
20
+ // 1. Create consent request
21
+ const createRes = await fetch(`${apiUrl}/v1/consent`, {
22
+ method: "POST",
23
+ headers: { "Content-Type": "application/json", "X-Torii-Key": apiKey },
24
+ body: JSON.stringify({ serverId, toolName, args }),
25
+ signal: AbortSignal.timeout(5_000),
26
+ });
27
+ if (!createRes.ok) {
28
+ process.stderr.write(`[torii/consent] failed to create request (${createRes.status}) — allowing\n`);
29
+ return "skipped";
30
+ }
31
+ const { id } = (await createRes.json());
32
+ process.stderr.write(`[torii/consent] ⏳ waiting for approval: ${serverId}__${toolName} (id=${id})\n`);
33
+ // 2. Long-poll for resolution (up to 60 s)
34
+ const waitRes = await fetch(`${apiUrl}/v1/consent/${id}/wait?timeout=60`, {
35
+ headers: { "X-Torii-Key": apiKey },
36
+ signal: AbortSignal.timeout(70_000), // 60 s server + 10 s network buffer
37
+ });
38
+ if (!waitRes.ok)
39
+ return "timeout";
40
+ const { status } = (await waitRes.json());
41
+ process.stderr.write(`[torii/consent] ${id} → ${status}\n`);
42
+ return status;
43
+ }
44
+ catch (err) {
45
+ process.stderr.write(`[torii/consent] error for ${serverId}__${toolName}: ${err} — allowing\n`);
46
+ return "skipped"; // fail open: if consent service is unreachable, don't block
47
+ }
48
+ }
49
+ //# sourceMappingURL=consent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consent.js","sourceRoot":"","sources":["../../src/security/consent.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,4DAA4D;AAE5D,MAAM,SAAS,GAAG;IAChB,8CAA8C;IAC9C,uCAAuC;IACvC,4CAA4C;IAC5C,6CAA6C;IAC7C,0CAA0C;CAC3C,CAAC;AAEF,MAAM,UAAU,UAAU,CAAC,QAAgB;IACzC,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AACjD,CAAC;AAMD,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAAgB,EAChB,QAAgB,EAChB,IAAa;IAEb,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IACzC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IAEzC,qDAAqD;IACrD,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAEzC,IAAI,CAAC;QACH,4BAA4B;QAC5B,MAAM,SAAS,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,aAAa,EAAE;YACpD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,EAAE;YACtE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;YAClD,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC;SACnC,CAAC,CAAC;QAEH,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC;YAClB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,6CAA6C,SAAS,CAAC,MAAM,gBAAgB,CAAC,CAAC;YACpG,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,EAAE,EAAE,EAAE,GAAG,CAAC,MAAM,SAAS,CAAC,IAAI,EAAE,CAAmB,CAAC;QAC1D,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,2CAA2C,QAAQ,KAAK,QAAQ,QAAQ,EAAE,KAAK,CAChF,CAAC;QAEF,2CAA2C;QAC3C,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,eAAe,EAAE,kBAAkB,EAAE;YACxE,OAAO,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE;YAClC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,oCAAoC;SAC1E,CAAC,CAAC;QAEH,IAAI,CAAC,OAAO,CAAC,EAAE;YAAE,OAAO,SAAS,CAAC;QAElC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,OAAO,CAAC,IAAI,EAAE,CAAuB,CAAC;QAChE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,EAAE,MAAM,MAAM,IAAI,CAAC,CAAC;QAE5D,OAAO,MAAkB,CAAC;IAC5B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,6BAA6B,QAAQ,KAAK,QAAQ,KAAK,GAAG,eAAe,CAC1E,CAAC;QACF,OAAO,SAAS,CAAC,CAAC,4DAA4D;IAChF,CAAC;AACH,CAAC"}
@@ -0,0 +1,22 @@
1
+ interface ArgsCondition {
2
+ field: string;
3
+ operator: "equals" | "contains" | "startsWith" | "endsWith" | "matches";
4
+ value: string;
5
+ }
6
+ export interface PolicyRule {
7
+ id: string;
8
+ name: string;
9
+ enabled: boolean;
10
+ serverPattern: string;
11
+ toolPattern: string;
12
+ argsCondition: ArgsCondition | null;
13
+ action: "deny" | "require_consent";
14
+ reason: string | null;
15
+ priority: number;
16
+ }
17
+ export declare function evaluatePolicy(serverId: string, toolName: string, args: unknown): PolicyRule | null;
18
+ export declare function loadPolicies(): Promise<void>;
19
+ export declare function startPolicyRefresh(intervalMs?: number): void;
20
+ export declare function getPolicies(): PolicyRule[];
21
+ export {};
22
+ //# sourceMappingURL=policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/security/policy.ts"],"names":[],"mappings":"AAQA,UAAU,aAAa;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,QAAQ,GAAG,UAAU,GAAG,YAAY,GAAG,UAAU,GAAG,SAAS,CAAC;IACxE,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,aAAa,GAAG,IAAI,CAAC;IACpC,MAAM,EAAE,MAAM,GAAG,iBAAiB,CAAC;IACnC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAgED,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,GACZ,UAAU,GAAG,IAAI,CAYnB;AAID,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAkBlD;AAED,wBAAgB,kBAAkB,CAAC,UAAU,SAAS,GAAG,IAAI,CAO5D;AAED,wBAAgB,WAAW,IAAI,UAAU,EAAE,CAE1C"}