airlock-bot 0.0.1 → 0.2.1

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 (334) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +336 -0
  3. package/airlock.service +27 -0
  4. package/dist/allowlist/engine.d.ts +9 -0
  5. package/dist/allowlist/engine.d.ts.map +1 -0
  6. package/dist/allowlist/engine.js +24 -0
  7. package/dist/allowlist/engine.js.map +1 -0
  8. package/dist/allowlist/pattern.d.ts +13 -0
  9. package/dist/allowlist/pattern.d.ts.map +1 -0
  10. package/dist/allowlist/pattern.js +33 -0
  11. package/dist/allowlist/pattern.js.map +1 -0
  12. package/dist/audit/api.d.ts +7 -0
  13. package/dist/audit/api.d.ts.map +1 -0
  14. package/dist/audit/api.js +31 -0
  15. package/dist/audit/api.js.map +1 -0
  16. package/dist/audit/db.d.ts +44 -0
  17. package/dist/audit/db.d.ts.map +1 -0
  18. package/dist/audit/db.js +121 -0
  19. package/dist/audit/db.js.map +1 -0
  20. package/dist/audit/logger.d.ts +25 -0
  21. package/dist/audit/logger.d.ts.map +1 -0
  22. package/dist/audit/logger.js +58 -0
  23. package/dist/audit/logger.js.map +1 -0
  24. package/dist/audit/redactor.d.ts +5 -0
  25. package/dist/audit/redactor.d.ts.map +1 -0
  26. package/dist/audit/redactor.js +27 -0
  27. package/dist/audit/redactor.js.map +1 -0
  28. package/dist/backend/cli/adapter.d.ts +23 -0
  29. package/dist/backend/cli/adapter.d.ts.map +1 -0
  30. package/dist/backend/cli/adapter.js +176 -0
  31. package/dist/backend/cli/adapter.js.map +1 -0
  32. package/dist/backend/cli/builder.d.ts +3 -0
  33. package/dist/backend/cli/builder.d.ts.map +1 -0
  34. package/dist/backend/cli/builder.js +52 -0
  35. package/dist/backend/cli/builder.js.map +1 -0
  36. package/dist/backend/cli/escaper.d.ts +2 -0
  37. package/dist/backend/cli/escaper.d.ts.map +1 -0
  38. package/dist/backend/cli/escaper.js +8 -0
  39. package/dist/backend/cli/escaper.js.map +1 -0
  40. package/dist/backend/exec-adapter.d.ts +13 -0
  41. package/dist/backend/exec-adapter.d.ts.map +1 -0
  42. package/dist/backend/exec-adapter.js +39 -0
  43. package/dist/backend/exec-adapter.js.map +1 -0
  44. package/dist/backend/factory.d.ts +9 -0
  45. package/dist/backend/factory.d.ts.map +1 -0
  46. package/dist/backend/factory.js +35 -0
  47. package/dist/backend/factory.js.map +1 -0
  48. package/dist/backend/http-adapter.d.ts +15 -0
  49. package/dist/backend/http-adapter.d.ts.map +1 -0
  50. package/dist/backend/http-adapter.js +39 -0
  51. package/dist/backend/http-adapter.js.map +1 -0
  52. package/dist/backend/mcp-adapter.d.ts +14 -0
  53. package/dist/backend/mcp-adapter.d.ts.map +1 -0
  54. package/dist/backend/mcp-adapter.js +38 -0
  55. package/dist/backend/mcp-adapter.js.map +1 -0
  56. package/dist/backend/openapi/adapter.d.ts +17 -0
  57. package/dist/backend/openapi/adapter.d.ts.map +1 -0
  58. package/dist/backend/openapi/adapter.js +144 -0
  59. package/dist/backend/openapi/adapter.js.map +1 -0
  60. package/dist/backend/openapi/parser.d.ts +21 -0
  61. package/dist/backend/openapi/parser.d.ts.map +1 -0
  62. package/dist/backend/openapi/parser.js +145 -0
  63. package/dist/backend/openapi/parser.js.map +1 -0
  64. package/dist/backend/types.d.ts +9 -0
  65. package/dist/backend/types.d.ts.map +1 -0
  66. package/dist/backend/types.js +2 -0
  67. package/dist/backend/types.js.map +1 -0
  68. package/dist/config/loader.d.ts +12 -0
  69. package/dist/config/loader.d.ts.map +1 -0
  70. package/dist/config/loader.js +178 -0
  71. package/dist/config/loader.js.map +1 -0
  72. package/dist/config/profiles.d.ts +12 -0
  73. package/dist/config/profiles.d.ts.map +1 -0
  74. package/dist/config/profiles.js +34 -0
  75. package/dist/config/profiles.js.map +1 -0
  76. package/dist/config/schema.d.ts +2034 -0
  77. package/dist/config/schema.d.ts.map +1 -0
  78. package/dist/config/schema.js +257 -0
  79. package/dist/config/schema.js.map +1 -0
  80. package/dist/config/watcher.d.ts +11 -0
  81. package/dist/config/watcher.d.ts.map +1 -0
  82. package/dist/config/watcher.js +39 -0
  83. package/dist/config/watcher.js.map +1 -0
  84. package/dist/discover/cli.d.ts +2 -0
  85. package/dist/discover/cli.d.ts.map +1 -0
  86. package/dist/discover/cli.js +97 -0
  87. package/dist/discover/cli.js.map +1 -0
  88. package/dist/discover/index.d.ts +19 -0
  89. package/dist/discover/index.d.ts.map +1 -0
  90. package/dist/discover/index.js +70 -0
  91. package/dist/discover/index.js.map +1 -0
  92. package/dist/discover/openapi.d.ts +9 -0
  93. package/dist/discover/openapi.d.ts.map +1 -0
  94. package/dist/discover/openapi.js +47 -0
  95. package/dist/discover/openapi.js.map +1 -0
  96. package/dist/discover/strategies/fig.d.ts +29 -0
  97. package/dist/discover/strategies/fig.d.ts.map +1 -0
  98. package/dist/discover/strategies/fig.js +82 -0
  99. package/dist/discover/strategies/fig.js.map +1 -0
  100. package/dist/discover/strategies/help-parser.d.ts +21 -0
  101. package/dist/discover/strategies/help-parser.d.ts.map +1 -0
  102. package/dist/discover/strategies/help-parser.js +121 -0
  103. package/dist/discover/strategies/help-parser.js.map +1 -0
  104. package/dist/discover/writer.d.ts +5 -0
  105. package/dist/discover/writer.d.ts.map +1 -0
  106. package/dist/discover/writer.js +14 -0
  107. package/dist/discover/writer.js.map +1 -0
  108. package/dist/gateway.d.ts +20 -0
  109. package/dist/gateway.d.ts.map +1 -0
  110. package/dist/gateway.js +125 -0
  111. package/dist/gateway.js.map +1 -0
  112. package/dist/hitl/api.d.ts +7 -0
  113. package/dist/hitl/api.d.ts.map +1 -0
  114. package/dist/hitl/api.js +35 -0
  115. package/dist/hitl/api.js.map +1 -0
  116. package/dist/hitl/batcher.d.ts +11 -0
  117. package/dist/hitl/batcher.d.ts.map +1 -0
  118. package/dist/hitl/batcher.js +37 -0
  119. package/dist/hitl/batcher.js.map +1 -0
  120. package/dist/hitl/engine.d.ts +36 -0
  121. package/dist/hitl/engine.d.ts.map +1 -0
  122. package/dist/hitl/engine.js +150 -0
  123. package/dist/hitl/engine.js.map +1 -0
  124. package/dist/hitl/formatter.d.ts +4 -0
  125. package/dist/hitl/formatter.d.ts.map +1 -0
  126. package/dist/hitl/formatter.js +31 -0
  127. package/dist/hitl/formatter.js.map +1 -0
  128. package/dist/hitl/parser.d.ts +7 -0
  129. package/dist/hitl/parser.d.ts.map +1 -0
  130. package/dist/hitl/parser.js +17 -0
  131. package/dist/hitl/parser.js.map +1 -0
  132. package/dist/hitl/provider-factory.d.ts +4 -0
  133. package/dist/hitl/provider-factory.d.ts.map +1 -0
  134. package/dist/hitl/provider-factory.js +42 -0
  135. package/dist/hitl/provider-factory.js.map +1 -0
  136. package/dist/hitl/providers/composite.d.ts +9 -0
  137. package/dist/hitl/providers/composite.d.ts.map +1 -0
  138. package/dist/hitl/providers/composite.js +23 -0
  139. package/dist/hitl/providers/composite.js.map +1 -0
  140. package/dist/hitl/providers/dashboard.d.ts +17 -0
  141. package/dist/hitl/providers/dashboard.d.ts.map +1 -0
  142. package/dist/hitl/providers/dashboard.js +210 -0
  143. package/dist/hitl/providers/dashboard.js.map +1 -0
  144. package/dist/hitl/providers/macos.d.ts +10 -0
  145. package/dist/hitl/providers/macos.d.ts.map +1 -0
  146. package/dist/hitl/providers/macos.js +65 -0
  147. package/dist/hitl/providers/macos.js.map +1 -0
  148. package/dist/hitl/providers/openclaw.d.ts +21 -0
  149. package/dist/hitl/providers/openclaw.d.ts.map +1 -0
  150. package/dist/hitl/providers/openclaw.js +106 -0
  151. package/dist/hitl/providers/openclaw.js.map +1 -0
  152. package/dist/hitl/providers/slack.d.ts +12 -0
  153. package/dist/hitl/providers/slack.d.ts.map +1 -0
  154. package/dist/hitl/providers/slack.js +24 -0
  155. package/dist/hitl/providers/slack.js.map +1 -0
  156. package/dist/hitl/providers/stdio.d.ts +12 -0
  157. package/dist/hitl/providers/stdio.d.ts.map +1 -0
  158. package/dist/hitl/providers/stdio.js +41 -0
  159. package/dist/hitl/providers/stdio.js.map +1 -0
  160. package/dist/hitl/providers/telegram.d.ts +22 -0
  161. package/dist/hitl/providers/telegram.d.ts.map +1 -0
  162. package/dist/hitl/providers/telegram.js +87 -0
  163. package/dist/hitl/providers/telegram.js.map +1 -0
  164. package/dist/hitl/providers/tui.d.ts +16 -0
  165. package/dist/hitl/providers/tui.d.ts.map +1 -0
  166. package/dist/hitl/providers/tui.js +169 -0
  167. package/dist/hitl/providers/tui.js.map +1 -0
  168. package/dist/hitl/providers/types.d.ts +18 -0
  169. package/dist/hitl/providers/types.d.ts.map +1 -0
  170. package/dist/hitl/providers/types.js +2 -0
  171. package/dist/hitl/providers/types.js.map +1 -0
  172. package/dist/hitl/providers/webhook.d.ts +13 -0
  173. package/dist/hitl/providers/webhook.d.ts.map +1 -0
  174. package/dist/hitl/providers/webhook.js +27 -0
  175. package/dist/hitl/providers/webhook.js.map +1 -0
  176. package/dist/index.d.ts +3 -0
  177. package/dist/index.d.ts.map +1 -0
  178. package/dist/index.js +103 -0
  179. package/dist/index.js.map +1 -0
  180. package/dist/middleware/chain-builder.d.ts +16 -0
  181. package/dist/middleware/chain-builder.d.ts.map +1 -0
  182. package/dist/middleware/chain-builder.js +139 -0
  183. package/dist/middleware/chain-builder.js.map +1 -0
  184. package/dist/middleware/compose.d.ts +3 -0
  185. package/dist/middleware/compose.d.ts.map +1 -0
  186. package/dist/middleware/compose.js +15 -0
  187. package/dist/middleware/compose.js.map +1 -0
  188. package/dist/middleware/core/allowlist.d.ts +3 -0
  189. package/dist/middleware/core/allowlist.d.ts.map +1 -0
  190. package/dist/middleware/core/allowlist.js +23 -0
  191. package/dist/middleware/core/allowlist.js.map +1 -0
  192. package/dist/middleware/core/exec-policy.d.ts +3 -0
  193. package/dist/middleware/core/exec-policy.d.ts.map +1 -0
  194. package/dist/middleware/core/exec-policy.js +30 -0
  195. package/dist/middleware/core/exec-policy.js.map +1 -0
  196. package/dist/middleware/core/execute.d.ts +3 -0
  197. package/dist/middleware/core/execute.d.ts.map +1 -0
  198. package/dist/middleware/core/execute.js +35 -0
  199. package/dist/middleware/core/execute.js.map +1 -0
  200. package/dist/middleware/core/hitl-gate.d.ts +3 -0
  201. package/dist/middleware/core/hitl-gate.d.ts.map +1 -0
  202. package/dist/middleware/core/hitl-gate.js +38 -0
  203. package/dist/middleware/core/hitl-gate.js.map +1 -0
  204. package/dist/middleware/core/rate-limiter.d.ts +10 -0
  205. package/dist/middleware/core/rate-limiter.d.ts.map +1 -0
  206. package/dist/middleware/core/rate-limiter.js +32 -0
  207. package/dist/middleware/core/rate-limiter.js.map +1 -0
  208. package/dist/middleware/core/schema-validator.d.ts +3 -0
  209. package/dist/middleware/core/schema-validator.d.ts.map +1 -0
  210. package/dist/middleware/core/schema-validator.js +31 -0
  211. package/dist/middleware/core/schema-validator.js.map +1 -0
  212. package/dist/middleware/detectors/injection-detector.d.ts +12 -0
  213. package/dist/middleware/detectors/injection-detector.d.ts.map +1 -0
  214. package/dist/middleware/detectors/injection-detector.js +129 -0
  215. package/dist/middleware/detectors/injection-detector.js.map +1 -0
  216. package/dist/middleware/detectors/sensitivity-classifier.d.ts +12 -0
  217. package/dist/middleware/detectors/sensitivity-classifier.d.ts.map +1 -0
  218. package/dist/middleware/detectors/sensitivity-classifier.js +125 -0
  219. package/dist/middleware/detectors/sensitivity-classifier.js.map +1 -0
  220. package/dist/middleware/post/canary-token-injector.d.ts +10 -0
  221. package/dist/middleware/post/canary-token-injector.d.ts.map +1 -0
  222. package/dist/middleware/post/canary-token-injector.js +53 -0
  223. package/dist/middleware/post/canary-token-injector.js.map +1 -0
  224. package/dist/middleware/post/output-injection-detector.d.ts +7 -0
  225. package/dist/middleware/post/output-injection-detector.d.ts.map +1 -0
  226. package/dist/middleware/post/output-injection-detector.js +46 -0
  227. package/dist/middleware/post/output-injection-detector.js.map +1 -0
  228. package/dist/middleware/post/output-size-limiter.d.ts +7 -0
  229. package/dist/middleware/post/output-size-limiter.d.ts.map +1 -0
  230. package/dist/middleware/post/output-size-limiter.js +47 -0
  231. package/dist/middleware/post/output-size-limiter.js.map +1 -0
  232. package/dist/middleware/post/output-summarizer.d.ts +15 -0
  233. package/dist/middleware/post/output-summarizer.d.ts.map +1 -0
  234. package/dist/middleware/post/output-summarizer.js +38 -0
  235. package/dist/middleware/post/output-summarizer.js.map +1 -0
  236. package/dist/middleware/post/strip-query-params.d.ts +3 -0
  237. package/dist/middleware/post/strip-query-params.d.ts.map +1 -0
  238. package/dist/middleware/post/strip-query-params.js +22 -0
  239. package/dist/middleware/post/strip-query-params.js.map +1 -0
  240. package/dist/middleware/post/untrusted-envelope.d.ts +3 -0
  241. package/dist/middleware/post/untrusted-envelope.d.ts.map +1 -0
  242. package/dist/middleware/post/untrusted-envelope.js +10 -0
  243. package/dist/middleware/post/untrusted-envelope.js.map +1 -0
  244. package/dist/middleware/types.d.ts +32 -0
  245. package/dist/middleware/types.d.ts.map +1 -0
  246. package/dist/middleware/types.js +2 -0
  247. package/dist/middleware/types.js.map +1 -0
  248. package/dist/pool/http-client.d.ts +26 -0
  249. package/dist/pool/http-client.d.ts.map +1 -0
  250. package/dist/pool/http-client.js +108 -0
  251. package/dist/pool/http-client.js.map +1 -0
  252. package/dist/pool/oauth-provider.d.ts +34 -0
  253. package/dist/pool/oauth-provider.d.ts.map +1 -0
  254. package/dist/pool/oauth-provider.js +135 -0
  255. package/dist/pool/oauth-provider.js.map +1 -0
  256. package/dist/pool/pool.d.ts +30 -0
  257. package/dist/pool/pool.d.ts.map +1 -0
  258. package/dist/pool/pool.js +119 -0
  259. package/dist/pool/pool.js.map +1 -0
  260. package/dist/pool/required-mcps.d.ts +7 -0
  261. package/dist/pool/required-mcps.d.ts.map +1 -0
  262. package/dist/pool/required-mcps.js +18 -0
  263. package/dist/pool/required-mcps.js.map +1 -0
  264. package/dist/pool/sse-client.d.ts +22 -0
  265. package/dist/pool/sse-client.d.ts.map +1 -0
  266. package/dist/pool/sse-client.js +69 -0
  267. package/dist/pool/sse-client.js.map +1 -0
  268. package/dist/pool/stdio-client.d.ts +24 -0
  269. package/dist/pool/stdio-client.d.ts.map +1 -0
  270. package/dist/pool/stdio-client.js +76 -0
  271. package/dist/pool/stdio-client.js.map +1 -0
  272. package/dist/registry/registry.d.ts +19 -0
  273. package/dist/registry/registry.d.ts.map +1 -0
  274. package/dist/registry/registry.js +85 -0
  275. package/dist/registry/registry.js.map +1 -0
  276. package/dist/registry/sanitizer.d.ts +2 -0
  277. package/dist/registry/sanitizer.d.ts.map +1 -0
  278. package/dist/registry/sanitizer.js +31 -0
  279. package/dist/registry/sanitizer.js.map +1 -0
  280. package/dist/security/blocked-hosts.d.ts +6 -0
  281. package/dist/security/blocked-hosts.d.ts.map +1 -0
  282. package/dist/security/blocked-hosts.js +26 -0
  283. package/dist/security/blocked-hosts.js.map +1 -0
  284. package/dist/security/domain-allowlist.d.ts +7 -0
  285. package/dist/security/domain-allowlist.d.ts.map +1 -0
  286. package/dist/security/domain-allowlist.js +19 -0
  287. package/dist/security/domain-allowlist.js.map +1 -0
  288. package/dist/stdio-mode.d.ts +3 -0
  289. package/dist/stdio-mode.d.ts.map +1 -0
  290. package/dist/stdio-mode.js +130 -0
  291. package/dist/stdio-mode.js.map +1 -0
  292. package/dist/tools/exec.d.ts +20 -0
  293. package/dist/tools/exec.d.ts.map +1 -0
  294. package/dist/tools/exec.js +105 -0
  295. package/dist/tools/exec.js.map +1 -0
  296. package/dist/tools/http.d.ts +13 -0
  297. package/dist/tools/http.d.ts.map +1 -0
  298. package/dist/tools/http.js +99 -0
  299. package/dist/tools/http.js.map +1 -0
  300. package/dist/transport/agent-server.d.ts +26 -0
  301. package/dist/transport/agent-server.d.ts.map +1 -0
  302. package/dist/transport/agent-server.js +54 -0
  303. package/dist/transport/agent-server.js.map +1 -0
  304. package/dist/transport/mcp-normalizer.d.ts +9 -0
  305. package/dist/transport/mcp-normalizer.d.ts.map +1 -0
  306. package/dist/transport/mcp-normalizer.js +12 -0
  307. package/dist/transport/mcp-normalizer.js.map +1 -0
  308. package/dist/transport/sse-server.d.ts +7 -0
  309. package/dist/transport/sse-server.d.ts.map +1 -0
  310. package/dist/transport/sse-server.js +94 -0
  311. package/dist/transport/sse-server.js.map +1 -0
  312. package/dist/transport/stdio-server.d.ts +3 -0
  313. package/dist/transport/stdio-server.d.ts.map +1 -0
  314. package/dist/transport/stdio-server.js +12 -0
  315. package/dist/transport/stdio-server.js.map +1 -0
  316. package/dist/types.d.ts +15 -0
  317. package/dist/types.d.ts.map +1 -0
  318. package/dist/types.js +2 -0
  319. package/dist/types.js.map +1 -0
  320. package/dist/util/id.d.ts +5 -0
  321. package/dist/util/id.d.ts.map +1 -0
  322. package/dist/util/id.js +16 -0
  323. package/dist/util/id.js.map +1 -0
  324. package/dist/util/logger.d.ts +4 -0
  325. package/dist/util/logger.d.ts.map +1 -0
  326. package/dist/util/logger.js +24 -0
  327. package/dist/util/logger.js.map +1 -0
  328. package/examples/claude-code-setup.md +77 -0
  329. package/examples/gateway.yaml +118 -0
  330. package/examples/local-dev.yaml +41 -0
  331. package/examples/openclaw-setup.md +51 -0
  332. package/examples/profiles.yaml +103 -0
  333. package/package.json +80 -3
  334. package/schema.json +943 -0
@@ -0,0 +1,130 @@
1
+ import { ClientPool } from './pool/pool.js';
2
+ import { requiredMcpsForAgent } from './pool/required-mcps.js';
3
+ import { ToolRegistry } from './registry/registry.js';
4
+ import { AllowlistEngine } from './allowlist/engine.js';
5
+ import { HitlEngine } from './hitl/engine.js';
6
+ import { HitlBatcher } from './hitl/batcher.js';
7
+ import { AuditLogger } from './audit/logger.js';
8
+ import { createHitlProvider } from './hitl/provider-factory.js';
9
+ import { runStdioServer } from './transport/stdio-server.js';
10
+ import { ConfigWatcher } from './config/watcher.js';
11
+ import { getMcpConfigs } from './config/schema.js';
12
+ import { buildAdapters } from './backend/factory.js';
13
+ import { childLogger } from './util/logger.js';
14
+ const log = childLogger('stdio-mode');
15
+ export async function runStdioMode(config, agentId, configPath) {
16
+ const agentConfig = config.agents[agentId];
17
+ if (!agentConfig) {
18
+ throw new Error(`Unknown agent profile: ${agentId}`);
19
+ }
20
+ // Stdio mode uses stdin/stdout for MCP protocol — the stdio approval provider
21
+ // also reads from stdin, which would corrupt the MCP transport.
22
+ const providers = Array.isArray(config.approvals.provider)
23
+ ? config.approvals.provider
24
+ : [config.approvals.provider];
25
+ if (providers.some((p) => p.type === 'stdio')) {
26
+ throw new Error('Cannot use approval provider "stdio" in stdio mode — both the MCP transport and approval ' +
27
+ 'provider would read from stdin. Use "telegram", "slack", "webhook", or "openclaw" instead.');
28
+ }
29
+ log.info({ agentId }, 'Starting Airlock in stdio mode');
30
+ let currentAgentConfig = agentConfig;
31
+ // Audit
32
+ const auditLogger = new AuditLogger(config.audit);
33
+ auditLogger.startDailyCleanup();
34
+ // Approvals — provider is created before engine, so forward calls via closure
35
+ // eslint-disable-next-line prefer-const
36
+ let hitlEngine;
37
+ const approvalForwarder = {
38
+ approve: (code) => hitlEngine.approve(code),
39
+ deny: (code, reason) => hitlEngine.deny(code, reason),
40
+ };
41
+ const hitlBatcher = new HitlBatcher(config.approvals.batch_window_ms);
42
+ const hitlProvider = createHitlProvider(config.approvals.provider, approvalForwarder);
43
+ hitlEngine = new HitlEngine(auditLogger, hitlProvider, config.approvals.timeout_ms);
44
+ hitlBatcher.onBatchReady((_agentId, requests) => {
45
+ void hitlProvider
46
+ .notify(requests)
47
+ .catch((err) => log.error({ err }, 'Failed to send approval notification'));
48
+ });
49
+ await hitlProvider.init();
50
+ await hitlEngine.recoverPending();
51
+ // Pool — only the MCPs this profile actually needs
52
+ const mcpConfigs = getMcpConfigs(config.providers);
53
+ const allMcpIds = Object.keys(mcpConfigs);
54
+ const neededIds = requiredMcpsForAgent(agentConfig, allMcpIds);
55
+ const filteredMcps = Object.fromEntries(neededIds.map((id) => [id, mcpConfigs[id]]));
56
+ log.info({ agentId, needed: neededIds, skipped: allMcpIds.filter((id) => !neededIds.includes(id)) }, 'Connecting to required MCPs only');
57
+ const pool = new ClientPool(filteredMcps);
58
+ pool.onClientReady((id) => {
59
+ log.info({ id }, 'MCP became ready, refreshing tool registry');
60
+ registry
61
+ .refresh()
62
+ .catch((err) => log.error({ err }, 'Failed to refresh registry after MCP ready'));
63
+ });
64
+ await pool.initialize();
65
+ // Build adapters from config (MCP, builtins, CLIs, APIs)
66
+ const adapters = buildAdapters(config, pool);
67
+ const allowlist = new AllowlistEngine(config.agents);
68
+ const registry = new ToolRegistry(adapters, allowlist, config.agents);
69
+ await registry.refresh();
70
+ // Hot reload — allowlists, agent config, security (not MCP connections or approval provider)
71
+ const watcher = new ConfigWatcher(configPath);
72
+ watcher.on('reload', (newConfig) => {
73
+ try {
74
+ if (newConfig.agents[agentId]) {
75
+ currentAgentConfig = newConfig.agents[agentId];
76
+ }
77
+ const newMcpConfigs = getMcpConfigs(newConfig.providers);
78
+ pool
79
+ .reload(newMcpConfigs)
80
+ .then(() => {
81
+ allowlist.reload(newConfig.agents);
82
+ registry.reloadAgents(newConfig.agents);
83
+ const newAdapters = buildAdapters(newConfig, pool);
84
+ registry.setAdapters(newAdapters);
85
+ return registry.refresh();
86
+ })
87
+ .then(() => {
88
+ log.info('Config reloaded: providers, allowlist, agent config, security');
89
+ })
90
+ .catch((err) => {
91
+ log.error({ err }, 'Failed to apply reloaded config');
92
+ });
93
+ }
94
+ catch (err) {
95
+ log.error({ err }, 'Failed to apply reloaded config');
96
+ }
97
+ });
98
+ watcher.start();
99
+ // Graceful shutdown
100
+ const shutdown = async () => {
101
+ log.info('Shutting down stdio mode');
102
+ try {
103
+ watcher.stop();
104
+ await registry.stopAll();
105
+ await pool.stop();
106
+ await hitlProvider.stop();
107
+ auditLogger.stop();
108
+ }
109
+ catch (err) {
110
+ log.error({ err }, 'Error during stdio shutdown');
111
+ }
112
+ process.exit(0);
113
+ };
114
+ process.on('SIGTERM', () => void shutdown());
115
+ process.on('SIGINT', () => void shutdown());
116
+ // No HTTP server — stdio only
117
+ await runStdioServer({
118
+ agentId,
119
+ agentConfig,
120
+ getAgentConfig: () => currentAgentConfig,
121
+ registry,
122
+ allowlist,
123
+ hitlEngine,
124
+ hitlBatcher,
125
+ hitlProvider,
126
+ auditLogger,
127
+ securityConfig: config.security,
128
+ });
129
+ }
130
+ //# sourceMappingURL=stdio-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdio-mode.js","sourceRoot":"","sources":["../src/stdio-mode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { AgentConfig } from '../config/schema.js';
2
+ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
3
+ export interface ExecResult {
4
+ exit_code: number | null;
5
+ stdout: string;
6
+ stderr: string;
7
+ duration_ms: number;
8
+ timed_out: boolean;
9
+ truncated?: boolean;
10
+ }
11
+ export type ExecDecision = 'allow' | 'ask' | 'deny';
12
+ export declare function buildExecTool(): Tool;
13
+ /**
14
+ * Reject commands containing shell metacharacters that could bypass
15
+ * the prefix-based allow/deny matching (e.g. chaining via ; && || | $()).
16
+ */
17
+ export declare function containsShellInjection(command: string): boolean;
18
+ export declare function evaluateExecCommand(command: string, agentConfig: AgentConfig): ExecDecision;
19
+ export declare function executeExec(command: string, agentConfig: AgentConfig, cwd?: string, timeoutMs?: number): Promise<ExecResult>;
20
+ //# sourceMappingURL=exec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/tools/exec.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAG/D,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AAOpD,wBAAgB,aAAa,IAAI,IAAI,CAcpC;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE/D;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,GAAG,YAAY,CAS3F;AAED,wBAAsB,WAAW,CAC/B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,WAAW,EACxB,GAAG,CAAC,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,UAAU,CAAC,CAmErB"}
@@ -0,0 +1,105 @@
1
+ import { spawn } from 'child_process';
2
+ import { matchesCommand } from '../allowlist/pattern.js';
3
+ const MAX_OUTPUT_BYTES = 10 * 1024 * 1024; // 10MB cap on stdout/stderr
4
+ /** Shell metacharacters that allow command chaining / injection */
5
+ const SHELL_INJECTION_RE = /[;|&`$(){}]/;
6
+ export function buildExecTool() {
7
+ return {
8
+ name: 'exec/run',
9
+ description: 'Run a shell command in a controlled environment',
10
+ inputSchema: {
11
+ type: 'object',
12
+ properties: {
13
+ command: { type: 'string', description: 'Shell command to run' },
14
+ cwd: { type: 'string', description: 'Working directory' },
15
+ timeout_ms: { type: 'number', description: 'Timeout in milliseconds' },
16
+ },
17
+ required: ['command'],
18
+ },
19
+ };
20
+ }
21
+ /**
22
+ * Reject commands containing shell metacharacters that could bypass
23
+ * the prefix-based allow/deny matching (e.g. chaining via ; && || | $()).
24
+ */
25
+ export function containsShellInjection(command) {
26
+ return SHELL_INJECTION_RE.test(command);
27
+ }
28
+ export function evaluateExecCommand(command, agentConfig) {
29
+ // Reject shell injection regardless of allow/deny patterns
30
+ if (containsShellInjection(command))
31
+ return 'deny';
32
+ // Deny takes priority
33
+ if (agentConfig.exec.deny.some((p) => matchesCommand(p, command)))
34
+ return 'deny';
35
+ if (agentConfig.exec.ask.some((p) => matchesCommand(p, command)))
36
+ return 'ask';
37
+ if (agentConfig.exec.allow.some((p) => matchesCommand(p, command)))
38
+ return 'allow';
39
+ return 'deny'; // fail-closed
40
+ }
41
+ export async function executeExec(command, agentConfig, cwd, timeoutMs) {
42
+ const timeout = timeoutMs ?? agentConfig.exec.default_timeout_ms;
43
+ const start = Date.now();
44
+ return new Promise((resolve, reject) => {
45
+ const child = spawn('/bin/sh', ['-c', command], {
46
+ cwd,
47
+ env: agentConfig.exec.env,
48
+ stdio: ['ignore', 'pipe', 'pipe'],
49
+ });
50
+ let stdout = '';
51
+ let stderr = '';
52
+ let timedOut = false;
53
+ let stdoutBytes = 0;
54
+ let stderrBytes = 0;
55
+ let truncated = false;
56
+ child.stdout.on('data', (chunk) => {
57
+ if (stdoutBytes < MAX_OUTPUT_BYTES) {
58
+ const remaining = MAX_OUTPUT_BYTES - stdoutBytes;
59
+ stdout += chunk.slice(0, remaining).toString();
60
+ }
61
+ else {
62
+ truncated = true;
63
+ }
64
+ stdoutBytes += chunk.length;
65
+ });
66
+ child.stderr.on('data', (chunk) => {
67
+ if (stderrBytes < MAX_OUTPUT_BYTES) {
68
+ const remaining = MAX_OUTPUT_BYTES - stderrBytes;
69
+ stderr += chunk.slice(0, remaining).toString();
70
+ }
71
+ else {
72
+ truncated = true;
73
+ }
74
+ stderrBytes += chunk.length;
75
+ });
76
+ const timer = setTimeout(() => {
77
+ timedOut = true;
78
+ child.kill('SIGTERM');
79
+ setTimeout(() => {
80
+ try {
81
+ child.kill('SIGKILL');
82
+ }
83
+ catch {
84
+ /* kill may fail — best effort */
85
+ }
86
+ }, 2000);
87
+ }, timeout);
88
+ child.on('close', (code) => {
89
+ clearTimeout(timer);
90
+ resolve({
91
+ exit_code: code,
92
+ stdout,
93
+ stderr,
94
+ duration_ms: Date.now() - start,
95
+ timed_out: timedOut,
96
+ truncated,
97
+ });
98
+ });
99
+ child.on('error', (err) => {
100
+ clearTimeout(timer);
101
+ reject(err);
102
+ });
103
+ });
104
+ }
105
+ //# sourceMappingURL=exec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec.js","sourceRoot":"","sources":["../../src/tools/exec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { AgentConfig, SecurityConfig } from '../config/schema.js';
2
+ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
3
+ export interface HttpResult {
4
+ status: number;
5
+ headers: Record<string, string>;
6
+ body: string;
7
+ truncated?: boolean;
8
+ }
9
+ export declare const HTTP_METHODS: readonly ["get", "post", "put", "patch", "delete", "head"];
10
+ export type HttpMethod = (typeof HTTP_METHODS)[number];
11
+ export declare function buildHttpTools(): Tool[];
12
+ export declare function executeHttp(method: HttpMethod, args: Record<string, unknown>, agentConfig: AgentConfig, securityConfig: SecurityConfig): Promise<HttpResult>;
13
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/tools/http.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAI/D,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,eAAO,MAAM,YAAY,4DAA6D,CAAC;AACvF,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvD,wBAAgB,cAAc,IAAI,IAAI,EAAE,CAmBvC;AAED,wBAAsB,WAAW,CAC/B,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,WAAW,EAAE,WAAW,EACxB,cAAc,EAAE,cAAc,GAC7B,OAAO,CAAC,UAAU,CAAC,CA+ErB"}
@@ -0,0 +1,99 @@
1
+ import { isBlockedHost } from '../security/blocked-hosts.js';
2
+ import { isDomainAllowed } from '../security/domain-allowlist.js';
3
+ const MAX_RESPONSE_BYTES = 1_048_576; // 1MB default
4
+ export const HTTP_METHODS = ['get', 'post', 'put', 'patch', 'delete', 'head'];
5
+ export function buildHttpTools() {
6
+ return HTTP_METHODS.map((method) => ({
7
+ name: `http/${method}`,
8
+ description: `HTTP ${method.toUpperCase()} request`,
9
+ inputSchema: {
10
+ type: 'object',
11
+ properties: {
12
+ url: { type: 'string', description: 'Full URL' },
13
+ headers: {
14
+ type: 'object',
15
+ description: 'Request headers',
16
+ additionalProperties: { type: 'string' },
17
+ },
18
+ body: { type: 'string', description: 'Request body (for POST/PUT/PATCH)' },
19
+ timeout_ms: { type: 'number', description: 'Timeout in milliseconds (default 30000)' },
20
+ },
21
+ required: ['url'],
22
+ },
23
+ }));
24
+ }
25
+ export async function executeHttp(method, args, agentConfig, securityConfig) {
26
+ const url = args['url'];
27
+ const headers = (args['headers'] ?? {});
28
+ const body = args['body'];
29
+ const timeoutMs = args['timeout_ms'] ?? agentConfig.http.timeout_ms;
30
+ const maxBytes = agentConfig.http.max_response_bytes ?? MAX_RESPONSE_BYTES;
31
+ let hostname;
32
+ try {
33
+ hostname = new URL(url).hostname;
34
+ }
35
+ catch {
36
+ throw new Error(`Invalid URL: ${url}`);
37
+ }
38
+ // Security checks
39
+ if (isBlockedHost(hostname, securityConfig.blocked_hosts, securityConfig.allowed_local)) {
40
+ throw new Error(`Blocked host: ${hostname}`);
41
+ }
42
+ if (!isDomainAllowed(hostname, agentConfig.http.domain_allowlist)) {
43
+ throw new Error(`Domain not in agent allowlist: ${hostname}`);
44
+ }
45
+ const controller = new AbortController();
46
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
47
+ try {
48
+ const response = await fetch(url, {
49
+ method: method.toUpperCase(),
50
+ headers,
51
+ body: ['post', 'put', 'patch'].includes(method) ? body : undefined,
52
+ signal: controller.signal,
53
+ redirect: 'manual',
54
+ });
55
+ clearTimeout(timer);
56
+ const responseHeaders = {};
57
+ response.headers.forEach((value, key) => {
58
+ responseHeaders[key] = value;
59
+ });
60
+ // Stream response with size cap instead of buffering entirely
61
+ let bodyText = '';
62
+ let truncated = false;
63
+ const reader = response.body?.getReader();
64
+ if (reader) {
65
+ let bytesRead = 0;
66
+ const decoder = new TextDecoder();
67
+ while (true) {
68
+ const { done, value } = (await reader.read());
69
+ if (done)
70
+ break;
71
+ bytesRead += value.byteLength;
72
+ if (bytesRead <= maxBytes) {
73
+ bodyText += decoder.decode(value, { stream: true });
74
+ }
75
+ else {
76
+ // Only include up to the limit
77
+ const overshoot = bytesRead - maxBytes;
78
+ const usable = value.byteLength - overshoot;
79
+ if (usable > 0) {
80
+ bodyText += decoder.decode(value.slice(0, usable), { stream: true });
81
+ }
82
+ truncated = true;
83
+ void reader.cancel();
84
+ break;
85
+ }
86
+ }
87
+ bodyText += decoder.decode(); // flush
88
+ }
89
+ return { status: response.status, headers: responseHeaders, body: bodyText, truncated };
90
+ }
91
+ catch (err) {
92
+ clearTimeout(timer);
93
+ if (err.name === 'AbortError') {
94
+ throw new Error(`HTTP request timed out after ${timeoutMs}ms`, { cause: err });
95
+ }
96
+ throw err;
97
+ }
98
+ }
99
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/tools/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+ import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
3
+ import type { ToolRegistry } from '../registry/registry.js';
4
+ import type { AllowlistEngine } from '../allowlist/engine.js';
5
+ import type { HitlEngine } from '../hitl/engine.js';
6
+ import type { HitlBatcher } from '../hitl/batcher.js';
7
+ import type { HitlProvider } from '../hitl/providers/types.js';
8
+ import type { AuditLogger } from '../audit/logger.js';
9
+ import type { AgentConfig, SecurityConfig } from '../config/schema.js';
10
+ import type { Middleware } from '../middleware/types.js';
11
+ export interface AgentServerDeps {
12
+ agentId: string;
13
+ agentConfig: AgentConfig;
14
+ getAgentConfig?: () => AgentConfig;
15
+ registry: ToolRegistry;
16
+ allowlist: AllowlistEngine;
17
+ hitlEngine: HitlEngine;
18
+ hitlBatcher: HitlBatcher;
19
+ hitlProvider: HitlProvider;
20
+ auditLogger: AuditLogger;
21
+ securityConfig?: SecurityConfig;
22
+ chain?: Middleware;
23
+ }
24
+ export declare function createAgentServer(deps: AgentServerDeps): Server;
25
+ export declare function connectAgentServer(server: Server, transport: Transport): Promise<void>;
26
+ //# sourceMappingURL=agent-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-server.d.ts","sourceRoot":"","sources":["../../src/transport/agent-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAEnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AAC/E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,KAAK,EAAE,UAAU,EAAmB,MAAM,wBAAwB,CAAC;AAI1E,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,WAAW,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,WAAW,CAAC;IACnC,QAAQ,EAAE,YAAY,CAAC;IACvB,SAAS,EAAE,eAAe,CAAC;IAC3B,UAAU,EAAE,UAAU,CAAC;IACvB,WAAW,EAAE,WAAW,CAAC;IACzB,YAAY,EAAE,YAAY,CAAC;IAC3B,WAAW,EAAE,WAAW,CAAC;IACzB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,KAAK,CAAC,EAAE,UAAU,CAAC;CACpB;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,CAsD/D;AAED,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5F"}
@@ -0,0 +1,54 @@
1
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+ import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
3
+ import { buildMiddlewareChain } from '../middleware/chain-builder.js';
4
+ import { generateId } from '../util/id.js';
5
+ export function createAgentServer(deps) {
6
+ const { agentId, registry, allowlist, hitlEngine, hitlBatcher, auditLogger } = deps;
7
+ const getConfig = deps.getAgentConfig ?? (() => deps.agentConfig);
8
+ const chain = deps.chain ??
9
+ buildMiddlewareChain(getConfig(), {
10
+ registry,
11
+ allowlist,
12
+ hitlEngine,
13
+ hitlBatcher,
14
+ auditLogger,
15
+ securityConfig: deps.securityConfig ?? { blocked_hosts: [], allowed_local: [] },
16
+ });
17
+ const server = new Server({ name: 'airlock', version: '0.1.0' }, { capabilities: { tools: {} } });
18
+ server.setRequestHandler(ListToolsRequestSchema, () => {
19
+ const tools = registry.getFiltered(agentId);
20
+ return { tools };
21
+ });
22
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
23
+ const toolName = request.params.name;
24
+ const args = request.params.arguments ?? {};
25
+ const ctx = {
26
+ callId: generateId(),
27
+ agentId,
28
+ agentConfig: getConfig(),
29
+ toolName,
30
+ args,
31
+ meta: {},
32
+ deps: {
33
+ registry,
34
+ allowlist,
35
+ hitlEngine,
36
+ hitlBatcher,
37
+ auditLogger,
38
+ securityConfig: deps.securityConfig ?? { blocked_hosts: [], allowed_local: [] },
39
+ },
40
+ startedAt: Date.now(),
41
+ };
42
+ const response = await chain(ctx, () => {
43
+ throw new Error('Middleware chain did not terminate — missing execute middleware');
44
+ });
45
+ return {
46
+ content: [{ type: 'text', text: response.text }],
47
+ };
48
+ });
49
+ return server;
50
+ }
51
+ export async function connectAgentServer(server, transport) {
52
+ await server.connect(transport);
53
+ }
54
+ //# sourceMappingURL=agent-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-server.js","sourceRoot":"","sources":["../../src/transport/agent-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAUnG,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAgB3C,MAAM,UAAU,iBAAiB,CAAC,IAAqB;IACrD,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;IACpF,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAElE,MAAM,KAAK,GACT,IAAI,CAAC,KAAK;QACV,oBAAoB,CAAC,SAAS,EAAE,EAAE;YAChC,QAAQ;YACR,SAAS;YACT,UAAU;YACV,WAAW;YACX,WAAW;YACX,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,EAAE,aAAa,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE;SAChF,CAAC,CAAC;IAEL,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IAElG,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,EAAE,GAAG,EAAE;QACpD,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAC5C,OAAO,EAAE,KAAK,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,iBAAiB,CAAC,qBAAqB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QAChE,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC;QACrC,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC;QAE5C,MAAM,GAAG,GAAoB;YAC3B,MAAM,EAAE,UAAU,EAAE;YACpB,OAAO;YACP,WAAW,EAAE,SAAS,EAAE;YACxB,QAAQ;YACR,IAAI;YACJ,IAAI,EAAE,EAAE;YACR,IAAI,EAAE;gBACJ,QAAQ;gBACR,SAAS;gBACT,UAAU;gBACV,WAAW;gBACX,WAAW;gBACX,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,EAAE,aAAa,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE;aAChF;YACD,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC;QAEF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE;YACrC,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;QACrF,CAAC,CAAC,CAAC;QAEH,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC;SACjD,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAAc,EAAE,SAAoB;IAC3E,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { ToolCall, ToolResult } from '../types.js';
2
+ export declare function callToolRequestToToolCall(name: string, args: Record<string, unknown>, agentId: string): ToolCall;
3
+ export declare function toolResultToCallToolResult(result: ToolResult): {
4
+ content: Array<{
5
+ type: 'text';
6
+ text: string;
7
+ }>;
8
+ };
9
+ //# sourceMappingURL=mcp-normalizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-normalizer.d.ts","sourceRoot":"","sources":["../../src/transport/mcp-normalizer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAExD,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,MAAM,GACd,QAAQ,CAEV;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,UAAU,GAAG;IAC9D,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChD,CAOA"}
@@ -0,0 +1,12 @@
1
+ export function callToolRequestToToolCall(name, args, agentId) {
2
+ return { tool: name, args, agentId };
3
+ }
4
+ export function toolResultToCallToolResult(result) {
5
+ if (!result.success) {
6
+ throw new Error(result.error ?? 'Unknown error');
7
+ }
8
+ return {
9
+ content: [{ type: 'text', text: JSON.stringify(result.data) }],
10
+ };
11
+ }
12
+ //# sourceMappingURL=mcp-normalizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-normalizer.js","sourceRoot":"","sources":["../../src/transport/mcp-normalizer.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,yBAAyB,CACvC,IAAY,EACZ,IAA6B,EAC7B,OAAe;IAEf,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,MAAkB;IAG3D,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,eAAe,CAAC,CAAC;IACnD,CAAC;IACD,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;KAC/D,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { FastifyInstance } from 'fastify';
2
+ import type { AgentServerDeps } from './agent-server.js';
3
+ export declare function sseServerPlugin(app: FastifyInstance, opts: {
4
+ getDeps: (agentId: string) => AgentServerDeps | undefined;
5
+ secret?: string;
6
+ }): Promise<void>;
7
+ //# sourceMappingURL=sse-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse-server.d.ts","sourceRoot":"","sources":["../../src/transport/sse-server.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAgC,MAAM,SAAS,CAAC;AAE7E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAazD,wBAAsB,eAAe,CACnC,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE;IACJ,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,eAAe,GAAG,SAAS,CAAC;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GACA,OAAO,CAAC,IAAI,CAAC,CA+Ff"}
@@ -0,0 +1,94 @@
1
+ import { timingSafeEqual } from 'crypto';
2
+ import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
3
+ import { createAgentServer, connectAgentServer } from './agent-server.js';
4
+ import { childLogger } from '../util/logger.js';
5
+ const log = childLogger('sse-server');
6
+ function constantTimeEqual(a, b) {
7
+ const bufA = Buffer.from(a);
8
+ const bufB = Buffer.from(b);
9
+ if (bufA.length !== bufB.length)
10
+ return false;
11
+ return timingSafeEqual(bufA, bufB);
12
+ }
13
+ // eslint-disable-next-line @typescript-eslint/require-await
14
+ export async function sseServerPlugin(app, opts) {
15
+ const { secret } = opts;
16
+ const sessions = new Map();
17
+ function checkAgentAuth(request, reply, deps) {
18
+ const token = deps.agentConfig.token;
19
+ if (token) {
20
+ const auth = request.headers.authorization ?? '';
21
+ if (!constantTimeEqual(auth, `Bearer ${token}`)) {
22
+ reply.status(401).send({ error: 'Unauthorized' });
23
+ return false;
24
+ }
25
+ return true;
26
+ }
27
+ // No per-agent token — fall back to global api_secret
28
+ if (secret) {
29
+ const auth = request.headers.authorization ?? '';
30
+ if (!constantTimeEqual(auth, `Bearer ${secret}`)) {
31
+ reply.status(401).send({ error: 'Unauthorized' });
32
+ return false;
33
+ }
34
+ }
35
+ return true;
36
+ }
37
+ // Auth for non-agent endpoints (management API)
38
+ app.addHook('preHandler', async (request, reply) => {
39
+ const url = request.url;
40
+ // Agent endpoints handle their own auth
41
+ if (url.startsWith('/agents/'))
42
+ return;
43
+ if (!secret)
44
+ return;
45
+ const auth = request.headers.authorization ?? '';
46
+ if (!constantTimeEqual(auth, `Bearer ${secret}`)) {
47
+ return reply.status(401).send({ error: 'Unauthorized' });
48
+ }
49
+ });
50
+ app.get('/agents/:profileId/sse', async (request, reply) => {
51
+ const { profileId } = request.params;
52
+ const deps = opts.getDeps(profileId);
53
+ if (!deps) {
54
+ return reply.status(404).send({ error: `Unknown agent profile: ${profileId}` });
55
+ }
56
+ if (!checkAgentAuth(request, reply, deps))
57
+ return;
58
+ log.info({ profileId }, 'New SSE connection');
59
+ const transport = new SSEServerTransport('/agents/' + profileId + '/messages', reply.raw);
60
+ sessions.set(transport.sessionId, { transport, profileId });
61
+ transport.onclose = () => {
62
+ sessions.delete(transport.sessionId);
63
+ log.info({ profileId, sessionId: transport.sessionId }, 'SSE session closed');
64
+ };
65
+ const server = createAgentServer(deps);
66
+ await connectAgentServer(server, transport);
67
+ // Clean up when client disconnects
68
+ request.raw.on('close', () => {
69
+ sessions.delete(transport.sessionId);
70
+ transport.close().catch(() => { });
71
+ });
72
+ });
73
+ app.post('/agents/:profileId/messages', async (request, reply) => {
74
+ const { profileId } = request.params;
75
+ const { sessionId } = request.query;
76
+ if (!sessionId) {
77
+ return reply.status(400).send({ error: 'sessionId query param required' });
78
+ }
79
+ const session = sessions.get(sessionId);
80
+ if (!session) {
81
+ return reply.status(404).send({ error: `Session not found: ${sessionId}` });
82
+ }
83
+ // Verify the session belongs to the profile in the URL
84
+ if (session.profileId !== profileId) {
85
+ return reply.status(403).send({ error: 'Session does not belong to this agent' });
86
+ }
87
+ // Check auth on message posts too
88
+ const deps = opts.getDeps(profileId);
89
+ if (!deps || !checkAgentAuth(request, reply, deps))
90
+ return;
91
+ await session.transport.handlePostMessage(request.raw, reply.raw);
92
+ });
93
+ }
94
+ //# sourceMappingURL=sse-server.js.map