@suveren/gateway 0.4.1 → 0.6.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 (137) hide show
  1. package/bin/suveren-gateway.js +86 -5
  2. package/content/integrations/calendar.json +116 -22
  3. package/content/integrations/deploy-github.json +164 -0
  4. package/content/integrations/gmail.json +13 -4
  5. package/content/integrations/index.json +2 -1
  6. package/dist/control-plane/index.mjs +84 -7
  7. package/dist/mcp-server/http.mjs +147 -21
  8. package/dist/ui/assets/index-DecSrutK.js +105 -0
  9. package/dist/ui/index.html +1 -1
  10. package/node_modules/@hap/core/dist/index.d.mts +21 -0
  11. package/node_modules/@hap/core/dist/index.d.ts +21 -0
  12. package/node_modules/@hap/core/dist/index.js +17 -0
  13. package/node_modules/@hap/core/dist/index.mjs +17 -0
  14. package/node_modules/@hap/core/package.json +1 -1
  15. package/node_modules/@hap/core/src/gatekeeper.ts +28 -0
  16. package/node_modules/@hap/core/src/types.ts +21 -0
  17. package/node_modules/fast-uri/index.js +37 -1
  18. package/node_modules/fast-uri/package.json +1 -1
  19. package/node_modules/fast-uri/test/security.test.js +136 -0
  20. package/node_modules/hono/dist/cjs/helper/proxy/index.js +4 -0
  21. package/node_modules/hono/dist/cjs/jsx/base.js +1 -9
  22. package/node_modules/hono/dist/cjs/jsx/hooks/index.js +14 -11
  23. package/node_modules/hono/dist/cjs/middleware/cors/index.js +1 -1
  24. package/node_modules/hono/dist/cjs/middleware/language/language.js +10 -6
  25. package/node_modules/hono/dist/cjs/utils/cookie.js +2 -1
  26. package/node_modules/hono/dist/helper/proxy/index.js +4 -0
  27. package/node_modules/hono/dist/jsx/base.js +1 -9
  28. package/node_modules/hono/dist/jsx/hooks/index.js +14 -11
  29. package/node_modules/hono/dist/middleware/cors/index.js +1 -1
  30. package/node_modules/hono/dist/middleware/language/language.js +10 -6
  31. package/node_modules/hono/dist/utils/cookie.js +2 -1
  32. package/node_modules/hono/package.json +2 -3
  33. package/node_modules/ip-address/README.md +142 -128
  34. package/node_modules/ip-address/dist/common.d.ts +6 -0
  35. package/node_modules/ip-address/dist/common.js +17 -1
  36. package/node_modules/ip-address/dist/common.js.map +1 -1
  37. package/node_modules/ip-address/dist/ipv4.js +3 -12
  38. package/node_modules/ip-address/dist/ipv4.js.map +1 -1
  39. package/node_modules/ip-address/dist/ipv6.d.ts +9 -2
  40. package/node_modules/ip-address/dist/ipv6.js +35 -16
  41. package/node_modules/ip-address/dist/ipv6.js.map +1 -1
  42. package/node_modules/ip-address/package.json +5 -3
  43. package/node_modules/jose/README.md +13 -13
  44. package/node_modules/jose/dist/types/index.d.ts +6 -5
  45. package/node_modules/jose/dist/types/jwe/compact/decrypt.d.ts +17 -11
  46. package/node_modules/jose/dist/types/jwe/compact/encrypt.d.ts +7 -19
  47. package/node_modules/jose/dist/types/jwe/flattened/decrypt.d.ts +17 -11
  48. package/node_modules/jose/dist/types/jwe/flattened/encrypt.d.ts +7 -19
  49. package/node_modules/jose/dist/types/jwe/general/decrypt.d.ts +18 -13
  50. package/node_modules/jose/dist/types/jwe/general/encrypt.d.ts +20 -21
  51. package/node_modules/jose/dist/types/jwk/embedded.d.ts +8 -12
  52. package/node_modules/jose/dist/types/jwk/thumbprint.d.ts +0 -15
  53. package/node_modules/jose/dist/types/jwks/local.d.ts +12 -21
  54. package/node_modules/jose/dist/types/jwks/remote.d.ts +34 -165
  55. package/node_modules/jose/dist/types/jws/compact/sign.d.ts +2 -13
  56. package/node_modules/jose/dist/types/jws/compact/verify.d.ts +17 -13
  57. package/node_modules/jose/dist/types/jws/flattened/sign.d.ts +2 -13
  58. package/node_modules/jose/dist/types/jws/flattened/verify.d.ts +17 -13
  59. package/node_modules/jose/dist/types/jws/general/sign.d.ts +16 -17
  60. package/node_modules/jose/dist/types/jws/general/verify.d.ts +18 -15
  61. package/node_modules/jose/dist/types/jwt/decrypt.d.ts +17 -11
  62. package/node_modules/jose/dist/types/jwt/encrypt.d.ts +10 -34
  63. package/node_modules/jose/dist/types/jwt/sign.d.ts +2 -13
  64. package/node_modules/jose/dist/types/jwt/unsecured.d.ts +4 -13
  65. package/node_modules/jose/dist/types/jwt/verify.d.ts +14 -13
  66. package/node_modules/jose/dist/types/key/export.d.ts +0 -14
  67. package/node_modules/jose/dist/types/key/generate_key_pair.d.ts +7 -14
  68. package/node_modules/jose/dist/types/key/generate_secret.d.ts +16 -14
  69. package/node_modules/jose/dist/types/key/import.d.ts +18 -28
  70. package/node_modules/jose/dist/types/types.d.ts +239 -222
  71. package/node_modules/jose/dist/types/util/base64url.d.ts +11 -4
  72. package/node_modules/jose/dist/types/util/decode_jwt.d.ts +1 -9
  73. package/node_modules/jose/dist/types/util/decode_protected_header.d.ts +0 -8
  74. package/node_modules/jose/dist/types/util/errors.d.ts +128 -121
  75. package/node_modules/jose/dist/webapi/jwe/compact/decrypt.js +4 -22
  76. package/node_modules/jose/dist/webapi/jwe/flattened/decrypt.js +5 -153
  77. package/node_modules/jose/dist/webapi/jwe/flattened/encrypt.js +16 -111
  78. package/node_modules/jose/dist/webapi/jwe/general/decrypt.js +15 -3
  79. package/node_modules/jose/dist/webapi/jwe/general/encrypt.js +65 -81
  80. package/node_modules/jose/dist/webapi/jwk/embedded.js +5 -3
  81. package/node_modules/jose/dist/webapi/jwks/local.js +31 -72
  82. package/node_modules/jose/dist/webapi/jwks/remote.js +19 -28
  83. package/node_modules/jose/dist/webapi/jws/compact/sign.js +5 -2
  84. package/node_modules/jose/dist/webapi/jws/compact/verify.js +4 -16
  85. package/node_modules/jose/dist/webapi/jws/flattened/sign.js +7 -65
  86. package/node_modules/jose/dist/webapi/jws/flattened/verify.js +3 -89
  87. package/node_modules/jose/dist/webapi/jws/general/sign.js +19 -15
  88. package/node_modules/jose/dist/webapi/jws/general/verify.js +29 -9
  89. package/node_modules/jose/dist/webapi/jwt/decrypt.js +5 -5
  90. package/node_modules/jose/dist/webapi/jwt/sign.js +2 -3
  91. package/node_modules/jose/dist/webapi/jwt/unsecured.js +4 -3
  92. package/node_modules/jose/dist/webapi/jwt/verify.js +6 -6
  93. package/node_modules/jose/dist/webapi/key/export.js +37 -4
  94. package/node_modules/jose/dist/webapi/key/generate_key_pair.js +33 -82
  95. package/node_modules/jose/dist/webapi/key/import.js +8 -8
  96. package/node_modules/jose/dist/webapi/lib/asn1.js +53 -122
  97. package/node_modules/jose/dist/webapi/lib/buffer_utils.js +1 -0
  98. package/node_modules/jose/dist/webapi/lib/content_encryption.js +34 -109
  99. package/node_modules/jose/dist/webapi/lib/crypto_key.js +18 -126
  100. package/node_modules/jose/dist/webapi/lib/helpers.js +23 -0
  101. package/node_modules/jose/dist/webapi/lib/invalid_key_input.js +0 -1
  102. package/node_modules/jose/dist/webapi/lib/jwe_algorithms.js +116 -0
  103. package/node_modules/jose/dist/webapi/lib/jwe_decrypt.js +186 -0
  104. package/node_modules/jose/dist/webapi/lib/jwe_encrypt.js +110 -0
  105. package/node_modules/jose/dist/webapi/lib/jwk_to_key.js +8 -98
  106. package/node_modules/jose/dist/webapi/lib/jws_algorithms.js +76 -0
  107. package/node_modules/jose/dist/webapi/lib/jws_sign.js +74 -0
  108. package/node_modules/jose/dist/webapi/lib/jws_verify.js +107 -0
  109. package/node_modules/jose/dist/webapi/lib/jwt_claims_set.js +68 -109
  110. package/node_modules/jose/dist/webapi/lib/key.js +132 -0
  111. package/node_modules/jose/dist/webapi/lib/key_algorithm.js +10 -0
  112. package/node_modules/jose/dist/webapi/lib/key_descriptor.js +7 -0
  113. package/node_modules/jose/dist/webapi/lib/key_management.js +162 -92
  114. package/node_modules/jose/dist/webapi/lib/options.js +48 -0
  115. package/node_modules/jose/dist/webapi/lib/signing.js +14 -56
  116. package/node_modules/jose/dist/webapi/lib/type_checks.js +13 -18
  117. package/node_modules/jose/dist/webapi/util/base64url.js +13 -4
  118. package/node_modules/jose/dist/webapi/util/decode_jwt.js +2 -2
  119. package/node_modules/jose/dist/webapi/util/decode_protected_header.js +5 -15
  120. package/node_modules/jose/dist/webapi/util/errors.js +1 -1
  121. package/node_modules/jose/package.json +2 -4
  122. package/package.json +2 -2
  123. package/profiles/deploy/0.6.profile.json +168 -0
  124. package/profiles/deploy/0.7.profile.json +168 -0
  125. package/profiles/email/0.4.profile.json +9 -2
  126. package/profiles/index.json +3 -1
  127. package/dist/ui/assets/index-Cog54HOo.js +0 -105
  128. package/node_modules/jose/dist/webapi/lib/aesgcmkw.js +0 -15
  129. package/node_modules/jose/dist/webapi/lib/aeskw.js +0 -25
  130. package/node_modules/jose/dist/webapi/lib/check_key_type.js +0 -122
  131. package/node_modules/jose/dist/webapi/lib/ecdhes.js +0 -52
  132. package/node_modules/jose/dist/webapi/lib/key_to_jwk.js +0 -34
  133. package/node_modules/jose/dist/webapi/lib/normalize_key.js +0 -166
  134. package/node_modules/jose/dist/webapi/lib/pbes2kw.js +0 -42
  135. package/node_modules/jose/dist/webapi/lib/rsaes.js +0 -24
  136. package/node_modules/jose/dist/webapi/lib/validate_algorithms.js +0 -10
  137. package/node_modules/jose/dist/webapi/lib/validate_crit.js +0 -33
@@ -11,6 +11,7 @@
11
11
  */
12
12
 
13
13
  import { spawn, spawnSync } from 'node:child_process';
14
+ import { createConnection } from 'node:net';
14
15
  import { existsSync, mkdirSync, openSync, readFileSync, writeFileSync, unlinkSync, statSync } from 'node:fs';
15
16
  import { homedir, platform } from 'node:os';
16
17
  import { dirname, join, resolve } from 'node:path';
@@ -60,6 +61,24 @@ async function start(args) {
60
61
  process.exit(1);
61
62
  }
62
63
 
64
+ // The PID file only knows about instances THIS CLI started. A gateway
65
+ // started by the login service — or from another shell — leaves none, so the
66
+ // check above passes, we spawn, the child dies instantly with EADDRINUSE,
67
+ // and its error goes only to the log. The user gets "started (pid N)" for a
68
+ // process that is already dead. Ask the port, not just the file.
69
+ if (await isPortListening(SUVEREN_PORT)) {
70
+ console.error(`Port ${SUVEREN_PORT} is already in use.`);
71
+ console.error(``);
72
+ console.error(`Something is already serving there — most likely a gateway started by the`);
73
+ console.error(`login service or from another terminal, which leaves no PID file for this`);
74
+ console.error(`CLI to find.`);
75
+ console.error(``);
76
+ console.error(` Check what it is: suveren-gateway status`);
77
+ console.error(` Stop a login service: suveren-gateway service uninstall`);
78
+ console.error(` Or use another port: SUVEREN_CP_PORT=3410 suveren-gateway start`);
79
+ process.exit(1);
80
+ }
81
+
63
82
  ensureDataDir();
64
83
 
65
84
  if (detach) {
@@ -71,6 +90,24 @@ async function start(args) {
71
90
  });
72
91
  writeFileSync(PID_FILE, String(child.pid), 'utf8');
73
92
  child.unref();
93
+
94
+ // "started" must mean SERVING. A detached child that dies on startup takes
95
+ // its error to the log, so reporting success on spawn alone hands the user
96
+ // a pid that no longer exists and a browser tab that will not connect.
97
+ const serving = await waitForListening(SUVEREN_PORT, 20_000);
98
+ if (!serving) {
99
+ safeUnlink(PID_FILE);
100
+ console.error(`suveren-gateway failed to start — nothing is listening on ${SUVEREN_PORT}.`);
101
+ console.error(``);
102
+ console.error(` Log: ${LOG_FILE}`);
103
+ console.error(` Last lines:`);
104
+ try {
105
+ const tail = readFileSync(LOG_FILE, 'utf8').trimEnd().split('\n').slice(-8);
106
+ for (const line of tail) console.error(` ${line}`);
107
+ } catch { /* no log yet */ }
108
+ process.exit(1);
109
+ }
110
+
74
111
  console.log(`suveren-gateway started (pid ${child.pid})`);
75
112
  console.log(``);
76
113
  console.log(` → Open in your browser: http://localhost:${SUVEREN_PORT}`);
@@ -313,14 +350,30 @@ async function serviceInstallMac() {
313
350
 
314
351
  const uid = process.getuid();
315
352
  // Clear any prior "disabled" mark from a previous uninstall, so the agent is
316
- // eligible again — but do NOT bootstrap it now: that would start a second
317
- // gateway alongside the running one and fight over the port.
353
+ // eligible again.
318
354
  runQuiet('launchctl', ['enable', `gui/${uid}/${LAUNCH_AGENT_LABEL}`]);
319
355
 
356
+ // Bootstrap NOW only when nothing is already serving. With a gateway running,
357
+ // loading the agent starts a second one that loses the port race and then
358
+ // crash-loops under KeepAlive — so in that case the agent waits for the next
359
+ // login, when the manual instance is gone. With nothing running there is no
360
+ // conflict, and waiting would leave the user with a "service" that isn't
361
+ // running and no obvious reason why.
362
+ const running = await isAlreadyRunning();
363
+ let loadedNow = false;
364
+ if (!running) {
365
+ const r = runQuiet('launchctl', ['bootstrap', `gui/${uid}`, plistPath]);
366
+ loadedNow = r.status === 0;
367
+ }
368
+
320
369
  console.log(`✓ Suveren gateway installed as a login service.`);
321
370
  console.log(``);
322
- console.log(` It starts automatically from your NEXT login, and restarts if it crashes.`);
323
- console.log(` Your current gateway keeps running nothing was interrupted.`);
371
+ if (loadedNow) {
372
+ console.log(` It is running now, starts automatically at login, and restarts if it crashes.`);
373
+ } else {
374
+ console.log(` It starts automatically from your NEXT login, and restarts if it crashes.`);
375
+ if (running) console.log(` Your current gateway keeps running — nothing was interrupted.`);
376
+ }
324
377
  console.log(` After a reboot it comes up LOCKED — open http://localhost:${SUVEREN_PORT} and`);
325
378
  console.log(` enter your Suveren API key once to unlock it (your key is never stored).`);
326
379
  console.log(``);
@@ -358,7 +411,13 @@ async function serviceStatusMac() {
358
411
  const state = /state = (\w+)/.exec(p.stdout || '');
359
412
  console.log(` launchd: loaded${state ? ` (${state[1]})` : ''}`);
360
413
  } else if (installed) {
361
- console.log(` launchd: not loaded (run \`suveren-gateway service install\` to (re)load)`);
414
+ // Do NOT point at `service install` here: install deliberately does not
415
+ // bootstrap while a gateway is already running (two would fight over the
416
+ // port), so re-running it would change nothing and the advice would be a
417
+ // dead end. Say plainly when it becomes active, and give the command that
418
+ // actually loads it now.
419
+ console.log(` launchd: not loaded — starts at your next login`);
420
+ console.log(` to activate now: suveren-gateway stop && launchctl bootstrap gui/$(id -u) "${plistPath}"`);
362
421
  }
363
422
  console.log('');
364
423
  await status(); // process/health/vault line
@@ -532,6 +591,28 @@ function serviceImplFor(os) {
532
591
  }
533
592
  }
534
593
 
594
+ /** Is something accepting TCP connections on this port? */
595
+ function isPortListening(port, timeoutMs = 1_000) {
596
+ return new Promise(resolve => {
597
+ const socket = createConnection({ host: '127.0.0.1', port: Number(port) });
598
+ const done = (result) => { socket.destroy(); resolve(result); };
599
+ socket.setTimeout(timeoutMs);
600
+ socket.once('connect', () => done(true));
601
+ socket.once('timeout', () => done(false));
602
+ socket.once('error', () => done(false));
603
+ });
604
+ }
605
+
606
+ /** Poll until the port accepts connections, or give up. */
607
+ async function waitForListening(port, timeoutMs) {
608
+ const deadline = Date.now() + timeoutMs;
609
+ while (Date.now() < deadline) {
610
+ if (await isPortListening(port, 500)) return true;
611
+ await sleep(300);
612
+ }
613
+ return false;
614
+ }
615
+
535
616
  /** Run a command capturing output, never throwing. */
536
617
  function runQuiet(bin, args) {
537
618
  const r = spawnSync(bin, args, { encoding: 'utf8' });
@@ -5,6 +5,9 @@
5
5
  "description": "List, create, update, and delete events in Google Calendar",
6
6
  "icon": "calendar",
7
7
  "profile": "calendar",
8
+ "readPolicy": {
9
+ "defaultAgeDays": 30
10
+ },
8
11
  "npmPackage": "@humanagencyp/google-calendar-mcp",
9
12
  "mcp": {
10
13
  "command": "google-calendar-mcp",
@@ -12,8 +15,18 @@
12
15
  },
13
16
  "credentials": {
14
17
  "fields": [
15
- { "key": "clientId", "label": "Client ID", "type": "text", "placeholder": "From Google Cloud Console" },
16
- { "key": "clientSecret", "label": "Client Secret", "type": "password", "placeholder": "OAuth2 client secret" }
18
+ {
19
+ "key": "clientId",
20
+ "label": "Client ID",
21
+ "type": "text",
22
+ "placeholder": "From Google Cloud Console"
23
+ },
24
+ {
25
+ "key": "clientSecret",
26
+ "label": "Client Secret",
27
+ "type": "password",
28
+ "placeholder": "OAuth2 client secret"
29
+ }
17
30
  ],
18
31
  "envMapping": {
19
32
  "GOOGLE_CLIENT_ID": "clientId",
@@ -30,9 +43,15 @@
30
43
  "https://www.googleapis.com/auth/calendar.events",
31
44
  "https://www.googleapis.com/auth/calendar.readonly"
32
45
  ],
33
- "credentialKeys": { "clientId": "clientId", "clientSecret": "clientSecret" },
46
+ "credentialKeys": {
47
+ "clientId": "clientId",
48
+ "clientSecret": "clientSecret"
49
+ },
34
50
  "tokenStorage": "refreshToken",
35
- "extraParams": { "access_type": "offline", "prompt": "consent" }
51
+ "extraParams": {
52
+ "access_type": "offline",
53
+ "prompt": "consent"
54
+ }
36
55
  },
37
56
  "contextDiscovery": {
38
57
  "allowed_calendars": {
@@ -53,52 +72,103 @@
53
72
  "toolGating": {
54
73
  "default": {
55
74
  "executionMapping": {},
56
- "staticExecution": { "duration": 0, "lookahead": 0 }
75
+ "staticExecution": {
76
+ "duration": 0,
77
+ "lookahead": 0
78
+ }
57
79
  },
58
80
  "overrides": {
59
81
  "list_calendars": {
60
82
  "category": "read",
61
- "read": { "resourceBound": "allowed_calendars", "resultResourcePath": "id" }
83
+ "read": {
84
+ "resourceBound": "allowed_calendars",
85
+ "resultResourcePath": "id"
86
+ }
62
87
  },
63
88
  "list_events": {
64
89
  "category": "read",
65
- "read": { "resourceBound": "allowed_calendars", "resourceArg": "calendarId", "resourceDefault": "primary" }
90
+ "read": {
91
+ "resourceBound": "allowed_calendars",
92
+ "resourceArg": "calendarId",
93
+ "resourceDefault": "primary",
94
+ "ageField": "read_age_days",
95
+ "ageFloorArg": "timeMin",
96
+ "ageFloorFormat": "iso"
97
+ }
66
98
  },
67
99
  "get_event": {
68
100
  "category": "read",
69
- "read": { "resourceBound": "allowed_calendars", "resourceArg": "calendarId", "resourceDefault": "primary" }
101
+ "read": {
102
+ "resourceBound": "allowed_calendars",
103
+ "resourceArg": "calendarId",
104
+ "resourceDefault": "primary",
105
+ "ageField": "read_age_days",
106
+ "resultDatePath": [
107
+ "start.dateTime",
108
+ "start.date"
109
+ ]
110
+ }
70
111
  },
71
112
  "free_busy": {
72
113
  "category": "read",
73
- "read": { "resourceBound": "allowed_calendars", "resourceArrayArg": "calendarIds", "resourceDefault": "primary" }
114
+ "read": {
115
+ "resourceBound": "allowed_calendars",
116
+ "resourceArrayArg": "calendarIds",
117
+ "resourceDefault": "primary",
118
+ "ageField": "read_age_days",
119
+ "ageFloorArg": "timeMin",
120
+ "ageFloorFormat": "iso"
121
+ }
74
122
  },
75
123
  "create_event": {
76
124
  "executionMapping": {
77
125
  "duration_minutes": "duration",
78
126
  "lookahead_days": "lookahead",
79
127
  "attendees": [
80
- { "field": "allowed_attendees", "transform": "join" },
81
- { "field": "allowed_domains", "transform": "join_domains" }
128
+ {
129
+ "field": "allowed_attendees",
130
+ "transform": "join"
131
+ },
132
+ {
133
+ "field": "allowed_domains",
134
+ "transform": "join_domains"
135
+ }
82
136
  ],
83
137
  "calendarId": "allowed_calendars"
84
138
  },
85
- "staticExecution": { "action_type": "booking" }
139
+ "staticExecution": {
140
+ "action_type": "booking"
141
+ }
86
142
  },
87
143
  "update_event": {
88
144
  "executionMapping": {
89
145
  "attendees": [
90
- { "field": "allowed_attendees", "transform": "join" },
91
- { "field": "allowed_domains", "transform": "join_domains" }
146
+ {
147
+ "field": "allowed_attendees",
148
+ "transform": "join"
149
+ },
150
+ {
151
+ "field": "allowed_domains",
152
+ "transform": "join_domains"
153
+ }
92
154
  ],
93
155
  "calendarId": "allowed_calendars"
94
156
  },
95
- "staticExecution": { "action_type": "booking", "duration": 0, "lookahead": 0 }
157
+ "staticExecution": {
158
+ "action_type": "booking",
159
+ "duration": 0,
160
+ "lookahead": 0
161
+ }
96
162
  },
97
163
  "delete_event": {
98
164
  "executionMapping": {
99
165
  "calendarId": "allowed_calendars"
100
166
  },
101
- "staticExecution": { "action_type": "delete", "duration": 0, "lookahead": 0 }
167
+ "staticExecution": {
168
+ "action_type": "delete",
169
+ "duration": 0,
170
+ "lookahead": 0
171
+ }
102
172
  }
103
173
  }
104
174
  },
@@ -108,22 +178,46 @@
108
178
  "description": "List and read events, check free/busy. No create, update, or delete.",
109
179
  "risk": "low",
110
180
  "mode": "automatic",
111
- "bounds": { "booking_daily_max": "0", "booking_duration_max": "0", "lookahead_days_max": "0" },
112
- "context": { "allowed_calendars": "primary", "allowed_attendees": "", "allowed_domains": "" },
181
+ "bounds": {
182
+ "booking_daily_max": "0",
183
+ "booking_duration_max": "0",
184
+ "lookahead_days_max": "0"
185
+ },
186
+ "context": {
187
+ "allowed_calendars": "primary",
188
+ "allowed_attendees": "",
189
+ "allowed_domains": ""
190
+ },
113
191
  "intent": "Allow the agent to read the primary calendar (only) to help with scheduling suggestions. No create or modify. To read other calendars, add them to allowed_calendars.",
114
192
  "ttl": 2592000,
115
- "tags": ["read-only", "30 days"]
193
+ "tags": [
194
+ "read-only",
195
+ "30 days"
196
+ ]
116
197
  },
117
198
  {
118
199
  "name": "Book with Review",
119
200
  "description": "Read events and propose new bookings. Every create/update/delete requires your approval.",
120
201
  "risk": "high",
121
202
  "mode": "review",
122
- "bounds": { "booking_daily_max": "3", "booking_duration_max": "120", "lookahead_days_max": "30" },
123
- "context": { "allowed_calendars": "primary", "allowed_attendees": "", "allowed_domains": "" },
203
+ "bounds": {
204
+ "booking_daily_max": "3",
205
+ "booking_duration_max": "120",
206
+ "lookahead_days_max": "30"
207
+ },
208
+ "context": {
209
+ "allowed_calendars": "primary",
210
+ "allowed_attendees": "",
211
+ "allowed_domains": ""
212
+ },
124
213
  "intent": "Read my calendar and propose bookings. Every create, update, or delete requires my review — I see the title, time, duration, and attendees before it goes through.",
125
214
  "ttl": 2592000,
126
- "tags": ["3 bookings/day", "2h max", "30d lookahead", "review mode"]
215
+ "tags": [
216
+ "3 bookings/day",
217
+ "2h max",
218
+ "30d lookahead",
219
+ "review mode"
220
+ ]
127
221
  }
128
222
  ],
129
223
  "setupHint": "Create OAuth credentials at Google Cloud Console and enable the Google Calendar API.",
@@ -0,0 +1,164 @@
1
+ {
2
+ "id": "deploy-github",
3
+ "name": "Deploy (GitHub)",
4
+ "version": "1.0.0",
5
+ "description": "Make an already-built version live, under signed authority",
6
+ "icon": "wrench",
7
+ "profile": "deploy",
8
+ "npmPackage": "@humanagencyp/deploy-mcp",
9
+ "mcp": {
10
+ "command": "npx",
11
+ "args": [
12
+ "-y",
13
+ "@humanagencyp/deploy-mcp@latest"
14
+ ]
15
+ },
16
+ "credentials": {
17
+ "fields": [
18
+ {
19
+ "key": "githubToken",
20
+ "label": "GitHub token",
21
+ "type": "password",
22
+ "placeholder": "github_pat_..."
23
+ }
24
+ ],
25
+ "envMapping": {
26
+ "GITHUB_TOKEN": "githubToken"
27
+ }
28
+ },
29
+ "oauth": null,
30
+ "toolGating": {
31
+ "default": {
32
+ "executionMapping": {},
33
+ "staticExecution": {},
34
+ "category": "disabled"
35
+ },
36
+ "overrides": {
37
+ "list_deployments": {
38
+ "category": "read",
39
+ "readGovernance": "none",
40
+ "readGovernanceReason": "Returns build metadata and the host's own deployment URLs. No source, no build output, no user content. Scoped to permitted repositories.",
41
+ "read": {
42
+ "resourceBound": "allowed_repos",
43
+ "resourceArg": "repo"
44
+ }
45
+ },
46
+ "get_deployment": {
47
+ "category": "read",
48
+ "readGovernance": "none",
49
+ "readGovernanceReason": "Returns metadata for one build — state, commit, URL. No build output.",
50
+ "read": {
51
+ "resourceBound": "allowed_repos",
52
+ "resourceArg": "repo"
53
+ }
54
+ },
55
+ "resolve_ref": {
56
+ "category": "read",
57
+ "readGovernance": "none",
58
+ "readGovernanceReason": "Returns a commit pointer only. Repository metadata, not user content.",
59
+ "read": {
60
+ "resourceBound": "allowed_repos",
61
+ "resourceArg": "repo"
62
+ }
63
+ },
64
+ "list_environments": {
65
+ "category": "read",
66
+ "readGovernance": "none",
67
+ "readGovernanceReason": "Returns environment names only. Repository configuration, needed so the owner can pick a target that exists.",
68
+ "read": {
69
+ "resourceBound": "allowed_repos",
70
+ "resourceArg": "repo"
71
+ }
72
+ },
73
+ "release": {
74
+ "executionMapping": {
75
+ "repo": "allowed_repos",
76
+ "environment": "allowed_environments",
77
+ "workflow": "allowed_workflows"
78
+ },
79
+ "staticExecution": {
80
+ "action_type": "release"
81
+ },
82
+ "contentField": "deployment_url"
83
+ }
84
+ }
85
+ },
86
+ "templates": [
87
+ {
88
+ "name": "Watch deployments",
89
+ "description": "See builds and their URLs. Cannot make anything live.",
90
+ "risk": "low",
91
+ "mode": "automatic",
92
+ "bounds": {
93
+ "release_daily_max": "0",
94
+ "rollback_allowed": "no"
95
+ },
96
+ "context": {
97
+ "allowed_repos": "",
98
+ "allowed_environments": "",
99
+ "allowed_workflows": "",
100
+ "allowed_branches": ""
101
+ },
102
+ "intent": "Let the agent see what has been built and whether it succeeded. It may not make anything live: a daily maximum of zero is a real limit, not an unset one. Fill in allowed_repos with the repositories it may look at.",
103
+ "ttl": 2592000,
104
+ "tags": [
105
+ "read-only",
106
+ "30 days"
107
+ ]
108
+ },
109
+ {
110
+ "name": "Release to production, review",
111
+ "description": "Make an existing build live after approval. Three a day, no rollback.",
112
+ "risk": "high",
113
+ "mode": "review",
114
+ "bounds": {
115
+ "release_daily_max": "3",
116
+ "rollback_allowed": "no"
117
+ },
118
+ "context": {
119
+ "allowed_repos": "",
120
+ "allowed_environments": "production",
121
+ "allowed_workflows": "deploy-website.yml",
122
+ "allowed_branches": "main"
123
+ },
124
+ "intent": "The agent may propose making a specific build live; nothing runs until I approve it. Open the build URL in the proposal and look at it before approving — that is the point of reviewing a release rather than a commit. Fill in allowed_repos, and check allowed_environments matches what the host actually calls it.",
125
+ "ttl": 2592000,
126
+ "tags": [
127
+ "review",
128
+ "production",
129
+ "30 days"
130
+ ]
131
+ }
132
+ ],
133
+ "setupHint": "Use a fine-grained token, scoped to one repository.",
134
+ "setupGuide": [
135
+ {
136
+ "title": "Create a fine-grained token",
137
+ "description": "GitHub Settings, Developer settings, Personal access tokens, Fine-grained. Not a classic token — those reach everything you own.",
138
+ "link": "https://github.com/settings/personal-access-tokens/new"
139
+ },
140
+ {
141
+ "title": "Scope it to one repository",
142
+ "description": "Under Repository access pick Only select repositories, then the repo to deploy."
143
+ },
144
+ {
145
+ "title": "Grant three permissions",
146
+ "description": "Actions: Read and write. Environments: Read. Contents: Read. Not Contents: Write — the agent ships commits, it never writes them."
147
+ },
148
+ {
149
+ "title": "Paste the token below",
150
+ "description": "Encrypted in your local vault. The agent never sees it."
151
+ }
152
+ ],
153
+ "proposalLinks": [
154
+ {
155
+ "label": "Open this build",
156
+ "template": "{deployment_url}",
157
+ "description": "Look at exactly what would go live"
158
+ },
159
+ {
160
+ "label": "View repository",
161
+ "template": "https://github.com/{repo}"
162
+ }
163
+ ]
164
+ }
@@ -6,6 +6,9 @@
6
6
  "icon": "mail",
7
7
  "profile": "email",
8
8
  "npmPackage": "@shinzolabs/gmail-mcp",
9
+ "readPolicy": {
10
+ "defaultAgeDays": 30
11
+ },
9
12
  "mcp": {
10
13
  "command": "gmail-mcp",
11
14
  "args": [],
@@ -80,7 +83,10 @@
80
83
  },
81
84
  "staticExecution": {
82
85
  "action_type": "send"
83
- }
86
+ },
87
+ "blockedArgs": [
88
+ "raw"
89
+ ]
84
90
  },
85
91
  "create_draft": {
86
92
  "executionMapping": {
@@ -101,7 +107,10 @@
101
107
  },
102
108
  "staticExecution": {
103
109
  "action_type": "send"
104
- }
110
+ },
111
+ "blockedArgs": [
112
+ "raw"
113
+ ]
105
114
  },
106
115
  "send_draft": {
107
116
  "executionMapping": {},
@@ -184,7 +193,7 @@
184
193
  "get_profile": {
185
194
  "category": "read",
186
195
  "readGovernance": "none",
187
- "readGovernanceReason": "Returns the account's own address and message counts the connector's own identity, no correspondence content."
196
+ "readGovernanceReason": "Returns the account's own address and message counts \u2014 the connector's own identity, no correspondence content."
188
197
  }
189
198
  }
190
199
  },
@@ -227,7 +236,7 @@
227
236
  "allowed_recipients": "",
228
237
  "allowed_domains": ""
229
238
  },
230
- "intent": "Read my inbox and compose emails. Every send requires my review I see the recipient, subject, and body before it goes out.",
239
+ "intent": "Read my inbox and compose emails. Every send requires my review \u2014 I see the recipient, subject, and body before it goes out.",
231
240
  "ttl": 2592000,
232
241
  "tags": [
233
242
  "5 recipients/email",
@@ -5,6 +5,7 @@
5
5
  "crm": "crm.json",
6
6
  "records": "records.json",
7
7
  "linkedin": "linkedin.json",
8
- "calendar": "calendar.json"
8
+ "calendar": "calendar.json",
9
+ "deploy-github": "deploy-github.json"
9
10
  }
10
11
  }