@adtl/gateway 0.1.1 → 0.3.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 (69) hide show
  1. package/README.md +57 -5
  2. package/dist/approvals.d.ts +97 -0
  3. package/dist/approvals.d.ts.map +1 -0
  4. package/dist/approvals.js +151 -0
  5. package/dist/approvals.js.map +1 -0
  6. package/dist/audit.d.ts +12 -2
  7. package/dist/audit.d.ts.map +1 -1
  8. package/dist/audit.js +1 -1
  9. package/dist/audit.js.map +1 -1
  10. package/dist/cli.js +46 -1
  11. package/dist/cli.js.map +1 -1
  12. package/dist/config.d.ts +346 -4
  13. package/dist/config.d.ts.map +1 -1
  14. package/dist/config.js +63 -2
  15. package/dist/config.js.map +1 -1
  16. package/dist/email.d.ts +35 -0
  17. package/dist/email.d.ts.map +1 -0
  18. package/dist/email.js +63 -0
  19. package/dist/email.js.map +1 -0
  20. package/dist/gateway.d.ts +33 -3
  21. package/dist/gateway.d.ts.map +1 -1
  22. package/dist/gateway.js +263 -23
  23. package/dist/gateway.js.map +1 -1
  24. package/dist/index.d.ts +4 -0
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +4 -0
  27. package/dist/index.js.map +1 -1
  28. package/dist/init/index.d.ts +4 -0
  29. package/dist/init/index.d.ts.map +1 -0
  30. package/dist/init/index.js +4 -0
  31. package/dist/init/index.js.map +1 -0
  32. package/dist/init/presets.d.ts +30 -0
  33. package/dist/init/presets.d.ts.map +1 -0
  34. package/dist/init/presets.js +34 -0
  35. package/dist/init/presets.js.map +1 -0
  36. package/dist/init/run.d.ts +18 -0
  37. package/dist/init/run.d.ts.map +1 -0
  38. package/dist/init/run.js +60 -0
  39. package/dist/init/run.js.map +1 -0
  40. package/dist/init/suggest.d.ts +50 -0
  41. package/dist/init/suggest.d.ts.map +1 -0
  42. package/dist/init/suggest.js +82 -0
  43. package/dist/init/suggest.js.map +1 -0
  44. package/dist/invoker.d.ts.map +1 -1
  45. package/dist/invoker.js +4 -2
  46. package/dist/invoker.js.map +1 -1
  47. package/dist/ntfy.d.ts +44 -0
  48. package/dist/ntfy.d.ts.map +1 -0
  49. package/dist/ntfy.js +133 -0
  50. package/dist/ntfy.js.map +1 -0
  51. package/dist/startup.d.ts +6 -1
  52. package/dist/startup.d.ts.map +1 -1
  53. package/dist/startup.js +37 -5
  54. package/dist/startup.js.map +1 -1
  55. package/package.json +4 -3
  56. package/src/approvals.ts +219 -0
  57. package/src/audit.ts +8 -3
  58. package/src/cli.ts +41 -1
  59. package/src/config.ts +65 -2
  60. package/src/email.ts +79 -0
  61. package/src/gateway.ts +324 -22
  62. package/src/index.ts +4 -0
  63. package/src/init/index.ts +3 -0
  64. package/src/init/presets.ts +64 -0
  65. package/src/init/run.ts +79 -0
  66. package/src/init/suggest.ts +127 -0
  67. package/src/invoker.ts +3 -2
  68. package/src/ntfy.ts +154 -0
  69. package/src/startup.ts +35 -4
package/dist/config.d.ts CHANGED
@@ -12,9 +12,16 @@
12
12
  * docs:
13
13
  * url: https://example.com/mcp
14
14
  * headers: { Authorization: "Bearer ${DOCS_TOKEN}" }
15
+ * approvals: # optional: make "ask" really ask
16
+ * timeoutSeconds: 50
17
+ * ntfy: { topic: "${ADTL_NTFY_TOPIC}" }
18
+ * email:
19
+ * smtp: { host: smtp.example.com, port: 465, user: "${SMTP_USER}", pass: "${SMTP_PASS}" }
20
+ * from: adtl@example.com
21
+ * to: you@example.com
15
22
  *
16
- * `${VAR}` in command, args, env, cwd, url and headers is replaced from the
17
- * gateway's environment. A missing variable is a config error.
23
+ * `${VAR}` in command, args, env, cwd, url, headers and approval settings is
24
+ * replaced from the gateway's environment. A missing variable is a config error.
18
25
  */
19
26
  import { z } from "zod";
20
27
  export declare const StdioUpstreamSchema: z.ZodObject<{
@@ -71,6 +78,184 @@ export declare const UpstreamSchema: z.ZodUnion<[z.ZodObject<{
71
78
  export type StdioUpstream = z.infer<typeof StdioUpstreamSchema>;
72
79
  export type HttpUpstream = z.infer<typeof HttpUpstreamSchema>;
73
80
  export type Upstream = z.infer<typeof UpstreamSchema>;
81
+ export declare const NtfyConfigSchema: z.ZodObject<{
82
+ server: z.ZodDefault<z.ZodString>;
83
+ /** Topic approval requests are sent to. Anyone who can read it can approve: keep it secret. */
84
+ topic: z.ZodString;
85
+ /** Topic answers are posted to. Default: `<topic>-reply`. */
86
+ replyTopic: z.ZodOptional<z.ZodString>;
87
+ token: z.ZodOptional<z.ZodString>;
88
+ }, "strict", z.ZodTypeAny, {
89
+ server: string;
90
+ topic: string;
91
+ replyTopic?: string | undefined;
92
+ token?: string | undefined;
93
+ }, {
94
+ topic: string;
95
+ server?: string | undefined;
96
+ replyTopic?: string | undefined;
97
+ token?: string | undefined;
98
+ }>;
99
+ export declare const EmailConfigSchema: z.ZodObject<{
100
+ smtp: z.ZodObject<{
101
+ host: z.ZodString;
102
+ port: z.ZodDefault<z.ZodNumber>;
103
+ /** TLS from the start. Default: true on port 465, otherwise STARTTLS. */
104
+ secure: z.ZodOptional<z.ZodBoolean>;
105
+ user: z.ZodOptional<z.ZodString>;
106
+ pass: z.ZodOptional<z.ZodString>;
107
+ }, "strict", z.ZodTypeAny, {
108
+ host: string;
109
+ port: number;
110
+ secure?: boolean | undefined;
111
+ user?: string | undefined;
112
+ pass?: string | undefined;
113
+ }, {
114
+ host: string;
115
+ port?: number | undefined;
116
+ secure?: boolean | undefined;
117
+ user?: string | undefined;
118
+ pass?: string | undefined;
119
+ }>;
120
+ from: z.ZodString;
121
+ to: z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "atleastone">]>;
122
+ on: z.ZodDefault<z.ZodArray<z.ZodEnum<["pending", "blocked", "approved", "denied", "timeout", "undeliverable"]>, "atleastone">>;
123
+ }, "strict", z.ZodTypeAny, {
124
+ smtp: {
125
+ host: string;
126
+ port: number;
127
+ secure?: boolean | undefined;
128
+ user?: string | undefined;
129
+ pass?: string | undefined;
130
+ };
131
+ from: string;
132
+ to: string | [string, ...string[]];
133
+ on: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]];
134
+ }, {
135
+ smtp: {
136
+ host: string;
137
+ port?: number | undefined;
138
+ secure?: boolean | undefined;
139
+ user?: string | undefined;
140
+ pass?: string | undefined;
141
+ };
142
+ from: string;
143
+ to: string | [string, ...string[]];
144
+ on?: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]] | undefined;
145
+ }>;
146
+ export declare const ApprovalsConfigSchema: z.ZodObject<{
147
+ /**
148
+ * How long a call waits for an answer; no answer means deny. Many MCP
149
+ * clients give up on a request after 60 seconds, hence the default.
150
+ */
151
+ timeoutSeconds: z.ZodDefault<z.ZodNumber>;
152
+ ntfy: z.ZodOptional<z.ZodObject<{
153
+ server: z.ZodDefault<z.ZodString>;
154
+ /** Topic approval requests are sent to. Anyone who can read it can approve: keep it secret. */
155
+ topic: z.ZodString;
156
+ /** Topic answers are posted to. Default: `<topic>-reply`. */
157
+ replyTopic: z.ZodOptional<z.ZodString>;
158
+ token: z.ZodOptional<z.ZodString>;
159
+ }, "strict", z.ZodTypeAny, {
160
+ server: string;
161
+ topic: string;
162
+ replyTopic?: string | undefined;
163
+ token?: string | undefined;
164
+ }, {
165
+ topic: string;
166
+ server?: string | undefined;
167
+ replyTopic?: string | undefined;
168
+ token?: string | undefined;
169
+ }>>;
170
+ email: z.ZodOptional<z.ZodObject<{
171
+ smtp: z.ZodObject<{
172
+ host: z.ZodString;
173
+ port: z.ZodDefault<z.ZodNumber>;
174
+ /** TLS from the start. Default: true on port 465, otherwise STARTTLS. */
175
+ secure: z.ZodOptional<z.ZodBoolean>;
176
+ user: z.ZodOptional<z.ZodString>;
177
+ pass: z.ZodOptional<z.ZodString>;
178
+ }, "strict", z.ZodTypeAny, {
179
+ host: string;
180
+ port: number;
181
+ secure?: boolean | undefined;
182
+ user?: string | undefined;
183
+ pass?: string | undefined;
184
+ }, {
185
+ host: string;
186
+ port?: number | undefined;
187
+ secure?: boolean | undefined;
188
+ user?: string | undefined;
189
+ pass?: string | undefined;
190
+ }>;
191
+ from: z.ZodString;
192
+ to: z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "atleastone">]>;
193
+ on: z.ZodDefault<z.ZodArray<z.ZodEnum<["pending", "blocked", "approved", "denied", "timeout", "undeliverable"]>, "atleastone">>;
194
+ }, "strict", z.ZodTypeAny, {
195
+ smtp: {
196
+ host: string;
197
+ port: number;
198
+ secure?: boolean | undefined;
199
+ user?: string | undefined;
200
+ pass?: string | undefined;
201
+ };
202
+ from: string;
203
+ to: string | [string, ...string[]];
204
+ on: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]];
205
+ }, {
206
+ smtp: {
207
+ host: string;
208
+ port?: number | undefined;
209
+ secure?: boolean | undefined;
210
+ user?: string | undefined;
211
+ pass?: string | undefined;
212
+ };
213
+ from: string;
214
+ to: string | [string, ...string[]];
215
+ on?: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]] | undefined;
216
+ }>>;
217
+ }, "strict", z.ZodTypeAny, {
218
+ timeoutSeconds: number;
219
+ ntfy?: {
220
+ server: string;
221
+ topic: string;
222
+ replyTopic?: string | undefined;
223
+ token?: string | undefined;
224
+ } | undefined;
225
+ email?: {
226
+ smtp: {
227
+ host: string;
228
+ port: number;
229
+ secure?: boolean | undefined;
230
+ user?: string | undefined;
231
+ pass?: string | undefined;
232
+ };
233
+ from: string;
234
+ to: string | [string, ...string[]];
235
+ on: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]];
236
+ } | undefined;
237
+ }, {
238
+ ntfy?: {
239
+ topic: string;
240
+ server?: string | undefined;
241
+ replyTopic?: string | undefined;
242
+ token?: string | undefined;
243
+ } | undefined;
244
+ email?: {
245
+ smtp: {
246
+ host: string;
247
+ port?: number | undefined;
248
+ secure?: boolean | undefined;
249
+ user?: string | undefined;
250
+ pass?: string | undefined;
251
+ };
252
+ from: string;
253
+ to: string | [string, ...string[]];
254
+ on?: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]] | undefined;
255
+ } | undefined;
256
+ timeoutSeconds?: number | undefined;
257
+ }>;
258
+ export type ApprovalsConfig = z.infer<typeof ApprovalsConfigSchema>;
74
259
  export declare const GatewayConfigSchema: z.ZodObject<{
75
260
  upstreams: z.ZodEffects<z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodObject<{
76
261
  command: z.ZodString;
@@ -153,6 +338,119 @@ export declare const GatewayConfigSchema: z.ZodObject<{
153
338
  * logs what would have been stopped: for trying a policy out safely.
154
339
  */
155
340
  mode: z.ZodDefault<z.ZodEnum<["active", "audit"]>>;
341
+ /** Human approvals for "ask" decisions. Without an answering channel, "ask" blocks. */
342
+ approvals: z.ZodOptional<z.ZodObject<{
343
+ /**
344
+ * How long a call waits for an answer; no answer means deny. Many MCP
345
+ * clients give up on a request after 60 seconds, hence the default.
346
+ */
347
+ timeoutSeconds: z.ZodDefault<z.ZodNumber>;
348
+ ntfy: z.ZodOptional<z.ZodObject<{
349
+ server: z.ZodDefault<z.ZodString>;
350
+ /** Topic approval requests are sent to. Anyone who can read it can approve: keep it secret. */
351
+ topic: z.ZodString;
352
+ /** Topic answers are posted to. Default: `<topic>-reply`. */
353
+ replyTopic: z.ZodOptional<z.ZodString>;
354
+ token: z.ZodOptional<z.ZodString>;
355
+ }, "strict", z.ZodTypeAny, {
356
+ server: string;
357
+ topic: string;
358
+ replyTopic?: string | undefined;
359
+ token?: string | undefined;
360
+ }, {
361
+ topic: string;
362
+ server?: string | undefined;
363
+ replyTopic?: string | undefined;
364
+ token?: string | undefined;
365
+ }>>;
366
+ email: z.ZodOptional<z.ZodObject<{
367
+ smtp: z.ZodObject<{
368
+ host: z.ZodString;
369
+ port: z.ZodDefault<z.ZodNumber>;
370
+ /** TLS from the start. Default: true on port 465, otherwise STARTTLS. */
371
+ secure: z.ZodOptional<z.ZodBoolean>;
372
+ user: z.ZodOptional<z.ZodString>;
373
+ pass: z.ZodOptional<z.ZodString>;
374
+ }, "strict", z.ZodTypeAny, {
375
+ host: string;
376
+ port: number;
377
+ secure?: boolean | undefined;
378
+ user?: string | undefined;
379
+ pass?: string | undefined;
380
+ }, {
381
+ host: string;
382
+ port?: number | undefined;
383
+ secure?: boolean | undefined;
384
+ user?: string | undefined;
385
+ pass?: string | undefined;
386
+ }>;
387
+ from: z.ZodString;
388
+ to: z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "atleastone">]>;
389
+ on: z.ZodDefault<z.ZodArray<z.ZodEnum<["pending", "blocked", "approved", "denied", "timeout", "undeliverable"]>, "atleastone">>;
390
+ }, "strict", z.ZodTypeAny, {
391
+ smtp: {
392
+ host: string;
393
+ port: number;
394
+ secure?: boolean | undefined;
395
+ user?: string | undefined;
396
+ pass?: string | undefined;
397
+ };
398
+ from: string;
399
+ to: string | [string, ...string[]];
400
+ on: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]];
401
+ }, {
402
+ smtp: {
403
+ host: string;
404
+ port?: number | undefined;
405
+ secure?: boolean | undefined;
406
+ user?: string | undefined;
407
+ pass?: string | undefined;
408
+ };
409
+ from: string;
410
+ to: string | [string, ...string[]];
411
+ on?: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]] | undefined;
412
+ }>>;
413
+ }, "strict", z.ZodTypeAny, {
414
+ timeoutSeconds: number;
415
+ ntfy?: {
416
+ server: string;
417
+ topic: string;
418
+ replyTopic?: string | undefined;
419
+ token?: string | undefined;
420
+ } | undefined;
421
+ email?: {
422
+ smtp: {
423
+ host: string;
424
+ port: number;
425
+ secure?: boolean | undefined;
426
+ user?: string | undefined;
427
+ pass?: string | undefined;
428
+ };
429
+ from: string;
430
+ to: string | [string, ...string[]];
431
+ on: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]];
432
+ } | undefined;
433
+ }, {
434
+ ntfy?: {
435
+ topic: string;
436
+ server?: string | undefined;
437
+ replyTopic?: string | undefined;
438
+ token?: string | undefined;
439
+ } | undefined;
440
+ email?: {
441
+ smtp: {
442
+ host: string;
443
+ port?: number | undefined;
444
+ secure?: boolean | undefined;
445
+ user?: string | undefined;
446
+ pass?: string | undefined;
447
+ };
448
+ from: string;
449
+ to: string | [string, ...string[]];
450
+ on?: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]] | undefined;
451
+ } | undefined;
452
+ timeoutSeconds?: number | undefined;
453
+ }>>;
156
454
  /** Timeout for each interceptor invocation, in milliseconds. */
157
455
  interceptorTimeoutMs: z.ZodDefault<z.ZodNumber>;
158
456
  }, "strict", z.ZodTypeAny, {
@@ -167,13 +465,34 @@ export declare const GatewayConfigSchema: z.ZodObject<{
167
465
  }>;
168
466
  mode: "audit" | "active";
169
467
  interceptorTimeoutMs: number;
170
- audit?: string | undefined;
171
468
  interceptors?: {
172
469
  command: string;
173
470
  args: string[];
174
471
  env: Record<string, string>;
175
472
  cwd?: string | undefined;
176
473
  } | undefined;
474
+ audit?: string | undefined;
475
+ approvals?: {
476
+ timeoutSeconds: number;
477
+ ntfy?: {
478
+ server: string;
479
+ topic: string;
480
+ replyTopic?: string | undefined;
481
+ token?: string | undefined;
482
+ } | undefined;
483
+ email?: {
484
+ smtp: {
485
+ host: string;
486
+ port: number;
487
+ secure?: boolean | undefined;
488
+ user?: string | undefined;
489
+ pass?: string | undefined;
490
+ };
491
+ from: string;
492
+ to: string | [string, ...string[]];
493
+ on: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]];
494
+ } | undefined;
495
+ } | undefined;
177
496
  }, {
178
497
  upstreams: Record<string, {
179
498
  command: string;
@@ -184,14 +503,35 @@ export declare const GatewayConfigSchema: z.ZodObject<{
184
503
  url: string;
185
504
  headers?: Record<string, string> | undefined;
186
505
  }>;
187
- audit?: string | undefined;
188
506
  interceptors?: {
189
507
  command: string;
190
508
  args?: string[] | undefined;
191
509
  env?: Record<string, string> | undefined;
192
510
  cwd?: string | undefined;
193
511
  } | undefined;
512
+ audit?: string | undefined;
194
513
  mode?: "audit" | "active" | undefined;
514
+ approvals?: {
515
+ ntfy?: {
516
+ topic: string;
517
+ server?: string | undefined;
518
+ replyTopic?: string | undefined;
519
+ token?: string | undefined;
520
+ } | undefined;
521
+ email?: {
522
+ smtp: {
523
+ host: string;
524
+ port?: number | undefined;
525
+ secure?: boolean | undefined;
526
+ user?: string | undefined;
527
+ pass?: string | undefined;
528
+ };
529
+ from: string;
530
+ to: string | [string, ...string[]];
531
+ on?: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]] | undefined;
532
+ } | undefined;
533
+ timeoutSeconds?: number | undefined;
534
+ } | undefined;
195
535
  interceptorTimeoutMs?: number | undefined;
196
536
  }>;
197
537
  export type GatewayConfig = z.infer<typeof GatewayConfigSchema>;
@@ -203,5 +543,7 @@ export declare class EnvExpansionError extends Error {
203
543
  /** Replace `${VAR}` with values from `env`. `$${VAR}` keeps a literal `${VAR}`. */
204
544
  export declare function expandEnv(value: string, env: NodeJS.ProcessEnv, where: string): string;
205
545
  export declare function expandUpstream<T extends Upstream>(id: string, u: T, env: NodeJS.ProcessEnv): T;
546
+ /** Expand `${VAR}` in every string of the approvals section. */
547
+ export declare function expandApprovals(a: ApprovalsConfig, env: NodeJS.ProcessEnv): ApprovalsConfig;
206
548
  export declare function isHttpUpstream(u: Upstream): u is HttpUpstream;
207
549
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;EAOrB,CAAC;AAEZ,eAAO,MAAM,kBAAkB;;;;;;;;;EAKpB,CAAC;AAEZ,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;IAAqD,CAAC;AACjF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAChE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAQ5B,8GAA8G;;;;;;;;;;;;;;;;;IAE9G,kGAAkG;;IAElG;;;OAGG;;IAEH,gEAAgE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGzD,CAAC;AACZ,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,cAAc,OAAO,CAAC;AAEnC,qBAAa,iBAAkB,SAAQ,KAAK;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM;gBAAhB,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAIrD;AAED,mFAAmF;AACnF,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAOtF;AAMD,wBAAgB,cAAc,CAAC,CAAC,SAAS,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,CAAC,CAY9F;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,QAAQ,GAAG,CAAC,IAAI,YAAY,CAE7D"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;EAOrB,CAAC;AAEZ,eAAO,MAAM,kBAAkB;;;;;;;;;EAKpB,CAAC;AAEZ,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;IAAqD,CAAC;AACjF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAChE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD,eAAO,MAAM,gBAAgB;;IAGzB,+FAA+F;;IAE/F,6DAA6D;;;;;;;;;;;;;EAItD,CAAC;AAEZ,eAAO,MAAM,iBAAiB;;;;QAMtB,yEAAyE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAUtE,CAAC;AAEZ,eAAO,MAAM,qBAAqB;IAE9B;;;OAGG;;;;QA/BH,+FAA+F;;QAE/F,6DAA6D;;;;;;;;;;;;;;;;;;YAYzD,yEAAyE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsBtE,CAAC;AACZ,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAQ5B,8GAA8G;;;;;;;;;;;;;;;;;IAE9G,kGAAkG;;IAElG;;;OAGG;;IAEH,uFAAuF;;QA5BvF;;;WAGG;;;;YA/BH,+FAA+F;;YAE/F,6DAA6D;;;;;;;;;;;;;;;;;;gBAYzD,yEAAyE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA4C7E,gEAAgE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGzD,CAAC;AACZ,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,cAAc,OAAO,CAAC;AAEnC,qBAAa,iBAAkB,SAAQ,KAAK;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM;gBAAhB,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAIrD;AAED,mFAAmF;AACnF,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAOtF;AAMD,wBAAgB,cAAc,CAAC,CAAC,SAAS,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,CAAC,CAY9F;AAED,gEAAgE;AAChE,wBAAgB,eAAe,CAAC,CAAC,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,eAAe,CAQ3F;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,QAAQ,GAAG,CAAC,IAAI,YAAY,CAE7D"}
package/dist/config.js CHANGED
@@ -12,11 +12,19 @@
12
12
  * docs:
13
13
  * url: https://example.com/mcp
14
14
  * headers: { Authorization: "Bearer ${DOCS_TOKEN}" }
15
+ * approvals: # optional: make "ask" really ask
16
+ * timeoutSeconds: 50
17
+ * ntfy: { topic: "${ADTL_NTFY_TOPIC}" }
18
+ * email:
19
+ * smtp: { host: smtp.example.com, port: 465, user: "${SMTP_USER}", pass: "${SMTP_PASS}" }
20
+ * from: adtl@example.com
21
+ * to: you@example.com
15
22
  *
16
- * `${VAR}` in command, args, env, cwd, url and headers is replaced from the
17
- * gateway's environment. A missing variable is a config error.
23
+ * `${VAR}` in command, args, env, cwd, url, headers and approval settings is
24
+ * replaced from the gateway's environment. A missing variable is a config error.
18
25
  */
19
26
  import { z } from "zod";
27
+ import { EMAIL_EVENTS } from "./email.js";
20
28
  const UPSTREAM_ID = /^[A-Za-z0-9-]+$/;
21
29
  export const StdioUpstreamSchema = z
22
30
  .object({
@@ -33,6 +41,44 @@ export const HttpUpstreamSchema = z
33
41
  })
34
42
  .strict();
35
43
  export const UpstreamSchema = z.union([StdioUpstreamSchema, HttpUpstreamSchema]);
44
+ export const NtfyConfigSchema = z
45
+ .object({
46
+ server: z.string().min(1).default("https://ntfy.sh"),
47
+ /** Topic approval requests are sent to. Anyone who can read it can approve: keep it secret. */
48
+ topic: z.string().min(1),
49
+ /** Topic answers are posted to. Default: `<topic>-reply`. */
50
+ replyTopic: z.string().min(1).optional(),
51
+ token: z.string().min(1).optional(),
52
+ })
53
+ .strict();
54
+ export const EmailConfigSchema = z
55
+ .object({
56
+ smtp: z
57
+ .object({
58
+ host: z.string().min(1),
59
+ port: z.number().int().positive().default(587),
60
+ /** TLS from the start. Default: true on port 465, otherwise STARTTLS. */
61
+ secure: z.boolean().optional(),
62
+ user: z.string().min(1).optional(),
63
+ pass: z.string().optional(),
64
+ })
65
+ .strict(),
66
+ from: z.string().min(1),
67
+ to: z.union([z.string().min(1), z.array(z.string().min(1)).nonempty()]),
68
+ on: z.array(z.enum(EMAIL_EVENTS)).nonempty().default(["pending", "blocked"]),
69
+ })
70
+ .strict();
71
+ export const ApprovalsConfigSchema = z
72
+ .object({
73
+ /**
74
+ * How long a call waits for an answer; no answer means deny. Many MCP
75
+ * clients give up on a request after 60 seconds, hence the default.
76
+ */
77
+ timeoutSeconds: z.number().int().positive().max(3600).default(50),
78
+ ntfy: NtfyConfigSchema.optional(),
79
+ email: EmailConfigSchema.optional(),
80
+ })
81
+ .strict();
36
82
  export const GatewayConfigSchema = z
37
83
  .object({
38
84
  upstreams: z
@@ -50,6 +96,8 @@ export const GatewayConfigSchema = z
50
96
  * logs what would have been stopped: for trying a policy out safely.
51
97
  */
52
98
  mode: z.enum(["active", "audit"]).default("active"),
99
+ /** Human approvals for "ask" decisions. Without an answering channel, "ask" blocks. */
100
+ approvals: ApprovalsConfigSchema.optional(),
53
101
  /** Timeout for each interceptor invocation, in milliseconds. */
54
102
  interceptorTimeoutMs: z.number().int().positive().default(5000),
55
103
  })
@@ -90,6 +138,19 @@ export function expandUpstream(id, u, env) {
90
138
  ...(u.cwd !== undefined ? { cwd: expandEnv(u.cwd, env, `${where}.cwd`) } : {}),
91
139
  };
92
140
  }
141
+ /** Expand `${VAR}` in every string of the approvals section. */
142
+ export function expandApprovals(a, env) {
143
+ const walk = (v, where) => {
144
+ if (typeof v === "string")
145
+ return expandEnv(v, env, where);
146
+ if (Array.isArray(v))
147
+ return v.map((x, i) => walk(x, `${where}[${i}]`));
148
+ if (v && typeof v === "object")
149
+ return Object.fromEntries(Object.entries(v).map(([k, x]) => [k, walk(x, `${where}.${k}`)]));
150
+ return v;
151
+ };
152
+ return walk(a, "gateway.approvals");
153
+ }
93
154
  export function isHttpUpstream(u) {
94
155
  return "url" in u;
95
156
  }
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { ApprovalEvent, Notifier } from "./approvals.js";
2
+ export declare const EMAIL_EVENTS: readonly ["pending", "blocked", "approved", "denied", "timeout", "undeliverable"];
3
+ export type EmailEvent = (typeof EMAIL_EVENTS)[number];
4
+ export interface MailSender {
5
+ sendMail(mail: {
6
+ from: string;
7
+ to: string[];
8
+ subject: string;
9
+ text: string;
10
+ }): Promise<unknown>;
11
+ }
12
+ export interface EmailOptions {
13
+ from: string;
14
+ to: string[];
15
+ /** Which events send an email. */
16
+ on: EmailEvent[];
17
+ /** SMTP settings, used unless `sender` is given. */
18
+ smtp?: {
19
+ host: string;
20
+ port: number;
21
+ secure?: boolean;
22
+ user?: string;
23
+ pass?: string;
24
+ };
25
+ sender?: MailSender;
26
+ }
27
+ export declare class EmailNotifier implements Notifier {
28
+ private readonly opts;
29
+ readonly name = "email";
30
+ private readonly sender;
31
+ constructor(opts: EmailOptions);
32
+ notify(event: ApprovalEvent): Promise<void>;
33
+ private compose;
34
+ }
35
+ //# sourceMappingURL=email.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email.d.ts","sourceRoot":"","sources":["../src/email.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE9D,eAAO,MAAM,YAAY,mFAAoF,CAAC;AAC9G,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,EAAE,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACjG;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,EAAE,CAAC;IACb,kCAAkC;IAClC,EAAE,EAAE,UAAU,EAAE,CAAC;IACjB,oDAAoD;IACpD,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACtF,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAED,qBAAa,aAAc,YAAW,QAAQ;IAIhC,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHjC,QAAQ,CAAC,IAAI,WAAW;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;gBAEP,IAAI,EAAE,YAAY;IAgBzC,MAAM,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAOjD,OAAO,CAAC,OAAO;CAwBhB"}
package/dist/email.js ADDED
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Email notices over SMTP. Notify only, on purpose: emails never contain
3
+ * approve links, because mail security scanners open links automatically and
4
+ * would approve calls by themselves. Approving happens on the push channel.
5
+ *
6
+ * Emails name the tool, server and reason, never arguments or results.
7
+ */
8
+ import nodemailer from "nodemailer";
9
+ export const EMAIL_EVENTS = ["pending", "blocked", "approved", "denied", "timeout", "undeliverable"];
10
+ export class EmailNotifier {
11
+ opts;
12
+ name = "email";
13
+ sender;
14
+ constructor(opts) {
15
+ this.opts = opts;
16
+ if (opts.sender) {
17
+ this.sender = opts.sender;
18
+ }
19
+ else if (opts.smtp) {
20
+ const { host, port, secure, user, pass } = opts.smtp;
21
+ this.sender = nodemailer.createTransport({
22
+ host,
23
+ port,
24
+ secure: secure ?? port === 465,
25
+ ...(user !== undefined ? { auth: { user, pass } } : {}),
26
+ });
27
+ }
28
+ else {
29
+ throw new Error("EmailNotifier needs smtp settings or a sender");
30
+ }
31
+ }
32
+ async notify(event) {
33
+ const kind = event.kind === "resolved" ? event.result.outcome : event.kind;
34
+ if (!this.opts.on.includes(kind))
35
+ return;
36
+ const { subject, text } = this.compose(event);
37
+ await this.sender.sendMail({ from: this.opts.from, to: this.opts.to, subject, text });
38
+ }
39
+ compose(event) {
40
+ const footer = "\n\n-- \nSent by ADTL (adtl-gateway). This email never contains approve links; approve on your push channel.";
41
+ if (event.kind === "blocked") {
42
+ return {
43
+ subject: `ADTL blocked ${event.server}.${event.tool}`,
44
+ text: `ADTL blocked a call to ${event.server}.${event.tool}.\n\nReason: ${event.reason}\nRule: ${event.matched.join(", ") || "default"}\nSession: ${event.sessionId}${footer}`,
45
+ };
46
+ }
47
+ const r = event.request;
48
+ const subject = `${r.server}.${r.tool}`;
49
+ if (event.kind === "pending") {
50
+ return {
51
+ subject: `ADTL: approval needed for ${subject}`,
52
+ text: `An agent wants to call ${subject} and ADTL needs your approval.\n\nReason: ${r.reason}\nRule: ${r.matched.join(", ") || "default"}\n` +
53
+ `Session: ${r.sessionId}\nExpires: ${r.expiresAt.toISOString()} (no answer means deny)${footer}`,
54
+ };
55
+ }
56
+ const res = event.result;
57
+ return {
58
+ subject: `ADTL: ${subject} ${res.outcome}`,
59
+ text: `The approval request for ${subject} was ${res.outcome}${res.channel ? ` via ${res.channel}` : ""} after ${Math.round(res.waitedMs / 1000)}s.\n\nReason it was asked: ${r.reason}\nSession: ${r.sessionId}${footer}`,
60
+ };
61
+ }
62
+ }
63
+ //# sourceMappingURL=email.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email.js","sourceRoot":"","sources":["../src/email.ts"],"names":[],"mappings":"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"}