@antasphere/chassis-server 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (798) hide show
  1. package/LICENSE +82 -0
  2. package/dist/accounts/deletion.d.ts +163 -0
  3. package/dist/accounts/deletion.d.ts.map +1 -0
  4. package/dist/accounts/deletion.js +360 -0
  5. package/dist/accounts/deletion.js.map +1 -0
  6. package/dist/accounts/erasure-log.d.ts +66 -0
  7. package/dist/accounts/erasure-log.d.ts.map +1 -0
  8. package/dist/accounts/erasure-log.js +117 -0
  9. package/dist/accounts/erasure-log.js.map +1 -0
  10. package/dist/accounts/index.d.ts +6 -0
  11. package/dist/accounts/index.d.ts.map +1 -0
  12. package/dist/accounts/index.js +6 -0
  13. package/dist/accounts/index.js.map +1 -0
  14. package/dist/accounts/mint-refusal.d.ts +47 -0
  15. package/dist/accounts/mint-refusal.d.ts.map +1 -0
  16. package/dist/accounts/mint-refusal.js +59 -0
  17. package/dist/accounts/mint-refusal.js.map +1 -0
  18. package/dist/accounts/signup-duplicate.d.ts +14 -0
  19. package/dist/accounts/signup-duplicate.d.ts.map +1 -0
  20. package/dist/accounts/signup-duplicate.js +25 -0
  21. package/dist/accounts/signup-duplicate.js.map +1 -0
  22. package/dist/accounts/superadmin.d.ts +27 -0
  23. package/dist/accounts/superadmin.d.ts.map +1 -0
  24. package/dist/accounts/superadmin.js +46 -0
  25. package/dist/accounts/superadmin.js.map +1 -0
  26. package/dist/api/apikeys.d.ts +14 -0
  27. package/dist/api/apikeys.d.ts.map +1 -0
  28. package/dist/api/apikeys.js +124 -0
  29. package/dist/api/apikeys.js.map +1 -0
  30. package/dist/api/audit.d.ts +4 -0
  31. package/dist/api/audit.d.ts.map +1 -0
  32. package/dist/api/audit.js +75 -0
  33. package/dist/api/audit.js.map +1 -0
  34. package/dist/api/break-glass.d.ts +48 -0
  35. package/dist/api/break-glass.d.ts.map +1 -0
  36. package/dist/api/break-glass.js +217 -0
  37. package/dist/api/break-glass.js.map +1 -0
  38. package/dist/api/cli-auth.d.ts +84 -0
  39. package/dist/api/cli-auth.d.ts.map +1 -0
  40. package/dist/api/cli-auth.js +177 -0
  41. package/dist/api/cli-auth.js.map +1 -0
  42. package/dist/api/create-api.d.ts +123 -0
  43. package/dist/api/create-api.d.ts.map +1 -0
  44. package/dist/api/create-api.js +1165 -0
  45. package/dist/api/create-api.js.map +1 -0
  46. package/dist/api/demo-passes.d.ts +45 -0
  47. package/dist/api/demo-passes.d.ts.map +1 -0
  48. package/dist/api/demo-passes.js +143 -0
  49. package/dist/api/demo-passes.js.map +1 -0
  50. package/dist/api/errors.d.ts +5 -0
  51. package/dist/api/errors.d.ts.map +1 -0
  52. package/dist/api/errors.js +5 -0
  53. package/dist/api/errors.js.map +1 -0
  54. package/dist/api/export.d.ts +63 -0
  55. package/dist/api/export.d.ts.map +1 -0
  56. package/dist/api/export.js +393 -0
  57. package/dist/api/export.js.map +1 -0
  58. package/dist/api/files.d.ts +40 -0
  59. package/dist/api/files.d.ts.map +1 -0
  60. package/dist/api/files.js +150 -0
  61. package/dist/api/files.js.map +1 -0
  62. package/dist/api/index.d.ts +17 -0
  63. package/dist/api/index.d.ts.map +1 -0
  64. package/dist/api/index.js +17 -0
  65. package/dist/api/index.js.map +1 -0
  66. package/dist/api/invitations.d.ts +50 -0
  67. package/dist/api/invitations.d.ts.map +1 -0
  68. package/dist/api/invitations.js +313 -0
  69. package/dist/api/invitations.js.map +1 -0
  70. package/dist/api/members.d.ts +25 -0
  71. package/dist/api/members.d.ts.map +1 -0
  72. package/dist/api/members.js +522 -0
  73. package/dist/api/members.js.map +1 -0
  74. package/dist/api/onboarding.d.ts +26 -0
  75. package/dist/api/onboarding.d.ts.map +1 -0
  76. package/dist/api/onboarding.js +23 -0
  77. package/dist/api/onboarding.js.map +1 -0
  78. package/dist/api/openapi-doc.d.ts +21 -0
  79. package/dist/api/openapi-doc.d.ts.map +1 -0
  80. package/dist/api/openapi-doc.js +25 -0
  81. package/dist/api/openapi-doc.js.map +1 -0
  82. package/dist/api/projects.d.ts +24 -0
  83. package/dist/api/projects.d.ts.map +1 -0
  84. package/dist/api/projects.js +624 -0
  85. package/dist/api/projects.js.map +1 -0
  86. package/dist/api/scope-routes.d.ts +12 -0
  87. package/dist/api/scope-routes.d.ts.map +1 -0
  88. package/dist/api/scope-routes.js +2 -0
  89. package/dist/api/scope-routes.js.map +1 -0
  90. package/dist/api/sso-connect.d.ts +70 -0
  91. package/dist/api/sso-connect.d.ts.map +1 -0
  92. package/dist/api/sso-connect.js +164 -0
  93. package/dist/api/sso-connect.js.map +1 -0
  94. package/dist/api/sso-logout.d.ts +41 -0
  95. package/dist/api/sso-logout.d.ts.map +1 -0
  96. package/dist/api/sso-logout.js +34 -0
  97. package/dist/api/sso-logout.js.map +1 -0
  98. package/dist/api/teams.d.ts +43 -0
  99. package/dist/api/teams.d.ts.map +1 -0
  100. package/dist/api/teams.js +447 -0
  101. package/dist/api/teams.js.map +1 -0
  102. package/dist/api/workspaces.d.ts +114 -0
  103. package/dist/api/workspaces.d.ts.map +1 -0
  104. package/dist/api/workspaces.js +462 -0
  105. package/dist/api/workspaces.js.map +1 -0
  106. package/dist/apikeys/index.d.ts +3 -0
  107. package/dist/apikeys/index.d.ts.map +1 -0
  108. package/dist/apikeys/index.js +3 -0
  109. package/dist/apikeys/index.js.map +1 -0
  110. package/dist/apikeys/peppers.d.ts +53 -0
  111. package/dist/apikeys/peppers.d.ts.map +1 -0
  112. package/dist/apikeys/peppers.js +97 -0
  113. package/dist/apikeys/peppers.js.map +1 -0
  114. package/dist/apikeys/service.d.ts +56 -0
  115. package/dist/apikeys/service.d.ts.map +1 -0
  116. package/dist/apikeys/service.js +196 -0
  117. package/dist/apikeys/service.js.map +1 -0
  118. package/dist/app.d.ts +65 -0
  119. package/dist/app.d.ts.map +1 -0
  120. package/dist/app.js +142 -0
  121. package/dist/app.js.map +1 -0
  122. package/dist/audit/filters.d.ts +38 -0
  123. package/dist/audit/filters.d.ts.map +1 -0
  124. package/dist/audit/filters.js +97 -0
  125. package/dist/audit/filters.js.map +1 -0
  126. package/dist/audit/index.d.ts +3 -0
  127. package/dist/audit/index.d.ts.map +1 -0
  128. package/dist/audit/index.js +3 -0
  129. package/dist/audit/index.js.map +1 -0
  130. package/dist/audit/service.d.ts +65 -0
  131. package/dist/audit/service.d.ts.map +1 -0
  132. package/dist/audit/service.js +103 -0
  133. package/dist/audit/service.js.map +1 -0
  134. package/dist/boot.d.ts +8 -0
  135. package/dist/boot.d.ts.map +1 -0
  136. package/dist/boot.js +822 -0
  137. package/dist/boot.js.map +1 -0
  138. package/dist/constant-time.d.ts +3 -0
  139. package/dist/constant-time.d.ts.map +1 -0
  140. package/dist/constant-time.js +10 -0
  141. package/dist/constant-time.js.map +1 -0
  142. package/dist/email/driver.d.ts +16 -0
  143. package/dist/email/driver.d.ts.map +1 -0
  144. package/dist/email/driver.js +136 -0
  145. package/dist/email/driver.js.map +1 -0
  146. package/dist/email/index.d.ts +4 -0
  147. package/dist/email/index.d.ts.map +1 -0
  148. package/dist/email/index.js +4 -0
  149. package/dist/email/index.js.map +1 -0
  150. package/dist/email/shell.d.ts +72 -0
  151. package/dist/email/shell.d.ts.map +1 -0
  152. package/dist/email/shell.js +146 -0
  153. package/dist/email/shell.js.map +1 -0
  154. package/dist/email/templates.d.ts +83 -0
  155. package/dist/email/templates.d.ts.map +1 -0
  156. package/dist/email/templates.js +96 -0
  157. package/dist/email/templates.js.map +1 -0
  158. package/dist/entitlements/check.d.ts +140 -0
  159. package/dist/entitlements/check.d.ts.map +1 -0
  160. package/dist/entitlements/check.js +276 -0
  161. package/dist/entitlements/check.js.map +1 -0
  162. package/dist/entitlements/clock-skew.d.ts +27 -0
  163. package/dist/entitlements/clock-skew.d.ts.map +1 -0
  164. package/dist/entitlements/clock-skew.js +58 -0
  165. package/dist/entitlements/clock-skew.js.map +1 -0
  166. package/dist/entitlements/gate.d.ts +113 -0
  167. package/dist/entitlements/gate.d.ts.map +1 -0
  168. package/dist/entitlements/gate.js +430 -0
  169. package/dist/entitlements/gate.js.map +1 -0
  170. package/dist/entitlements/hub-machine-token.d.ts +83 -0
  171. package/dist/entitlements/hub-machine-token.d.ts.map +1 -0
  172. package/dist/entitlements/hub-machine-token.js +175 -0
  173. package/dist/entitlements/hub-machine-token.js.map +1 -0
  174. package/dist/entitlements/hub-subject.d.ts +32 -0
  175. package/dist/entitlements/hub-subject.d.ts.map +1 -0
  176. package/dist/entitlements/hub-subject.js +68 -0
  177. package/dist/entitlements/hub-subject.js.map +1 -0
  178. package/dist/entitlements/index.d.ts +9 -0
  179. package/dist/entitlements/index.d.ts.map +1 -0
  180. package/dist/entitlements/index.js +9 -0
  181. package/dist/entitlements/index.js.map +1 -0
  182. package/dist/entitlements/poster.d.ts +81 -0
  183. package/dist/entitlements/poster.d.ts.map +1 -0
  184. package/dist/entitlements/poster.js +169 -0
  185. package/dist/entitlements/poster.js.map +1 -0
  186. package/dist/entitlements/profiles.d.ts +121 -0
  187. package/dist/entitlements/profiles.d.ts.map +1 -0
  188. package/dist/entitlements/profiles.js +212 -0
  189. package/dist/entitlements/profiles.js.map +1 -0
  190. package/dist/entitlements/slot.d.ts +33 -0
  191. package/dist/entitlements/slot.d.ts.map +1 -0
  192. package/dist/entitlements/slot.js +75 -0
  193. package/dist/entitlements/slot.js.map +1 -0
  194. package/dist/env.d.ts +293 -0
  195. package/dist/env.d.ts.map +1 -0
  196. package/dist/env.js +383 -0
  197. package/dist/env.js.map +1 -0
  198. package/dist/files/http.d.ts +23 -0
  199. package/dist/files/http.d.ts.map +1 -0
  200. package/dist/files/http.js +66 -0
  201. package/dist/files/http.js.map +1 -0
  202. package/dist/files/index.d.ts +5 -0
  203. package/dist/files/index.d.ts.map +1 -0
  204. package/dist/files/index.js +5 -0
  205. package/dist/files/index.js.map +1 -0
  206. package/dist/files/serve.d.ts +43 -0
  207. package/dist/files/serve.d.ts.map +1 -0
  208. package/dist/files/serve.js +71 -0
  209. package/dist/files/serve.js.map +1 -0
  210. package/dist/files/service.d.ts +69 -0
  211. package/dist/files/service.d.ts.map +1 -0
  212. package/dist/files/service.js +188 -0
  213. package/dist/files/service.js.map +1 -0
  214. package/dist/files/spool.d.ts +21 -0
  215. package/dist/files/spool.d.ts.map +1 -0
  216. package/dist/files/spool.js +47 -0
  217. package/dist/files/spool.js.map +1 -0
  218. package/dist/identity/better-auth.d.ts +3927 -0
  219. package/dist/identity/better-auth.d.ts.map +1 -0
  220. package/dist/identity/better-auth.js +896 -0
  221. package/dist/identity/better-auth.js.map +1 -0
  222. package/dist/identity/demo-pass-plugin.d.ts +29 -0
  223. package/dist/identity/demo-pass-plugin.d.ts.map +1 -0
  224. package/dist/identity/demo-pass-plugin.js +88 -0
  225. package/dist/identity/demo-pass-plugin.js.map +1 -0
  226. package/dist/identity/demo-pass-rules.d.ts +84 -0
  227. package/dist/identity/demo-pass-rules.d.ts.map +1 -0
  228. package/dist/identity/demo-pass-rules.js +223 -0
  229. package/dist/identity/demo-pass-rules.js.map +1 -0
  230. package/dist/identity/demo-pass.d.ts +159 -0
  231. package/dist/identity/demo-pass.d.ts.map +1 -0
  232. package/dist/identity/demo-pass.js +319 -0
  233. package/dist/identity/demo-pass.js.map +1 -0
  234. package/dist/identity/hub-grant.d.ts +182 -0
  235. package/dist/identity/hub-grant.d.ts.map +1 -0
  236. package/dist/identity/hub-grant.js +594 -0
  237. package/dist/identity/hub-grant.js.map +1 -0
  238. package/dist/identity/hub-jwt.d.ts +22 -0
  239. package/dist/identity/hub-jwt.d.ts.map +1 -0
  240. package/dist/identity/hub-jwt.js +77 -0
  241. package/dist/identity/hub-jwt.js.map +1 -0
  242. package/dist/identity/hub-live-gate.d.ts +17 -0
  243. package/dist/identity/hub-live-gate.d.ts.map +1 -0
  244. package/dist/identity/hub-live-gate.js +146 -0
  245. package/dist/identity/hub-live-gate.js.map +1 -0
  246. package/dist/identity/hub-logout.d.ts +88 -0
  247. package/dist/identity/hub-logout.d.ts.map +1 -0
  248. package/dist/identity/hub-logout.js +158 -0
  249. package/dist/identity/hub-logout.js.map +1 -0
  250. package/dist/identity/hub-projection.d.ts +103 -0
  251. package/dist/identity/hub-projection.d.ts.map +1 -0
  252. package/dist/identity/hub-projection.js +130 -0
  253. package/dist/identity/hub-projection.js.map +1 -0
  254. package/dist/identity/hub-reconcile.d.ts +151 -0
  255. package/dist/identity/hub-reconcile.d.ts.map +1 -0
  256. package/dist/identity/hub-reconcile.js +400 -0
  257. package/dist/identity/hub-reconcile.js.map +1 -0
  258. package/dist/identity/hub-sso.d.ts +363 -0
  259. package/dist/identity/hub-sso.d.ts.map +1 -0
  260. package/dist/identity/hub-sso.js +536 -0
  261. package/dist/identity/hub-sso.js.map +1 -0
  262. package/dist/identity/hub-user-client.d.ts +222 -0
  263. package/dist/identity/hub-user-client.d.ts.map +1 -0
  264. package/dist/identity/hub-user-client.js +406 -0
  265. package/dist/identity/hub-user-client.js.map +1 -0
  266. package/dist/identity/index.d.ts +13 -0
  267. package/dist/identity/index.d.ts.map +1 -0
  268. package/dist/identity/index.js +13 -0
  269. package/dist/identity/index.js.map +1 -0
  270. package/dist/identity/oauth-jwt.d.ts +32 -0
  271. package/dist/identity/oauth-jwt.d.ts.map +1 -0
  272. package/dist/identity/oauth-jwt.js +122 -0
  273. package/dist/identity/oauth-jwt.js.map +1 -0
  274. package/dist/identity/resolve-membership.d.ts +28 -0
  275. package/dist/identity/resolve-membership.d.ts.map +1 -0
  276. package/dist/identity/resolve-membership.js +69 -0
  277. package/dist/identity/resolve-membership.js.map +1 -0
  278. package/dist/identity/signing-key.d.ts +49 -0
  279. package/dist/identity/signing-key.d.ts.map +1 -0
  280. package/dist/identity/signing-key.js +144 -0
  281. package/dist/identity/signing-key.js.map +1 -0
  282. package/dist/index.d.ts +21 -0
  283. package/dist/index.d.ts.map +1 -0
  284. package/dist/index.js +11 -0
  285. package/dist/index.js.map +1 -0
  286. package/dist/invitations/index.d.ts +2 -0
  287. package/dist/invitations/index.d.ts.map +1 -0
  288. package/dist/invitations/index.js +2 -0
  289. package/dist/invitations/index.js.map +1 -0
  290. package/dist/invitations/service.d.ts +36 -0
  291. package/dist/invitations/service.d.ts.map +1 -0
  292. package/dist/invitations/service.js +122 -0
  293. package/dist/invitations/service.js.map +1 -0
  294. package/dist/jobs/index.d.ts +3 -0
  295. package/dist/jobs/index.d.ts.map +1 -0
  296. package/dist/jobs/index.js +3 -0
  297. package/dist/jobs/index.js.map +1 -0
  298. package/dist/jobs/pgboss.d.ts +119 -0
  299. package/dist/jobs/pgboss.d.ts.map +1 -0
  300. package/dist/jobs/pgboss.js +521 -0
  301. package/dist/jobs/pgboss.js.map +1 -0
  302. package/dist/jobs/timers.d.ts +127 -0
  303. package/dist/jobs/timers.d.ts.map +1 -0
  304. package/dist/jobs/timers.js +228 -0
  305. package/dist/jobs/timers.js.map +1 -0
  306. package/dist/logger.d.ts +17 -0
  307. package/dist/logger.d.ts.map +1 -0
  308. package/dist/logger.js +64 -0
  309. package/dist/logger.js.map +1 -0
  310. package/dist/mcp/errors.d.ts +37 -0
  311. package/dist/mcp/errors.d.ts.map +1 -0
  312. package/dist/mcp/errors.js +77 -0
  313. package/dist/mcp/errors.js.map +1 -0
  314. package/dist/mcp/http.d.ts +35 -0
  315. package/dist/mcp/http.d.ts.map +1 -0
  316. package/dist/mcp/http.js +80 -0
  317. package/dist/mcp/http.js.map +1 -0
  318. package/dist/mcp/index.d.ts +8 -0
  319. package/dist/mcp/index.d.ts.map +1 -0
  320. package/dist/mcp/index.js +8 -0
  321. package/dist/mcp/index.js.map +1 -0
  322. package/dist/mcp/inputs.d.ts +19 -0
  323. package/dist/mcp/inputs.d.ts.map +1 -0
  324. package/dist/mcp/inputs.js +28 -0
  325. package/dist/mcp/inputs.js.map +1 -0
  326. package/dist/mcp/projects.d.ts +31 -0
  327. package/dist/mcp/projects.d.ts.map +1 -0
  328. package/dist/mcp/projects.js +315 -0
  329. package/dist/mcp/projects.js.map +1 -0
  330. package/dist/mcp/server.d.ts +52 -0
  331. package/dist/mcp/server.d.ts.map +1 -0
  332. package/dist/mcp/server.js +93 -0
  333. package/dist/mcp/server.js.map +1 -0
  334. package/dist/mcp/teams.d.ts +7 -0
  335. package/dist/mcp/teams.d.ts.map +1 -0
  336. package/dist/mcp/teams.js +62 -0
  337. package/dist/mcp/teams.js.map +1 -0
  338. package/dist/mcp/tool-kit.d.ts +67 -0
  339. package/dist/mcp/tool-kit.d.ts.map +1 -0
  340. package/dist/mcp/tool-kit.js +74 -0
  341. package/dist/mcp/tool-kit.js.map +1 -0
  342. package/dist/members/removal.d.ts +95 -0
  343. package/dist/members/removal.d.ts.map +1 -0
  344. package/dist/members/removal.js +143 -0
  345. package/dist/members/removal.js.map +1 -0
  346. package/dist/middleware/auth-body.d.ts +25 -0
  347. package/dist/middleware/auth-body.d.ts.map +1 -0
  348. package/dist/middleware/auth-body.js +55 -0
  349. package/dist/middleware/auth-body.js.map +1 -0
  350. package/dist/middleware/auth-context.d.ts +170 -0
  351. package/dist/middleware/auth-context.d.ts.map +1 -0
  352. package/dist/middleware/auth-context.js +251 -0
  353. package/dist/middleware/auth-context.js.map +1 -0
  354. package/dist/middleware/body-cap.d.ts +17 -0
  355. package/dist/middleware/body-cap.d.ts.map +1 -0
  356. package/dist/middleware/body-cap.js +31 -0
  357. package/dist/middleware/body-cap.js.map +1 -0
  358. package/dist/middleware/body-refusal.d.ts +20 -0
  359. package/dist/middleware/body-refusal.d.ts.map +1 -0
  360. package/dist/middleware/body-refusal.js +5 -0
  361. package/dist/middleware/body-refusal.js.map +1 -0
  362. package/dist/middleware/cross-site.d.ts +61 -0
  363. package/dist/middleware/cross-site.d.ts.map +1 -0
  364. package/dist/middleware/cross-site.js +59 -0
  365. package/dist/middleware/cross-site.js.map +1 -0
  366. package/dist/middleware/hub-managed.d.ts +45 -0
  367. package/dist/middleware/hub-managed.d.ts.map +1 -0
  368. package/dist/middleware/hub-managed.js +56 -0
  369. package/dist/middleware/hub-managed.js.map +1 -0
  370. package/dist/middleware/idempotency.d.ts +14 -0
  371. package/dist/middleware/idempotency.d.ts.map +1 -0
  372. package/dist/middleware/idempotency.js +222 -0
  373. package/dist/middleware/idempotency.js.map +1 -0
  374. package/dist/middleware/index.d.ts +12 -0
  375. package/dist/middleware/index.d.ts.map +1 -0
  376. package/dist/middleware/index.js +12 -0
  377. package/dist/middleware/index.js.map +1 -0
  378. package/dist/middleware/json-depth.d.ts +32 -0
  379. package/dist/middleware/json-depth.d.ts.map +1 -0
  380. package/dist/middleware/json-depth.js +80 -0
  381. package/dist/middleware/json-depth.js.map +1 -0
  382. package/dist/middleware/no-store.d.ts +21 -0
  383. package/dist/middleware/no-store.d.ts.map +1 -0
  384. package/dist/middleware/no-store.js +32 -0
  385. package/dist/middleware/no-store.js.map +1 -0
  386. package/dist/middleware/oauth-public.d.ts +16 -0
  387. package/dist/middleware/oauth-public.d.ts.map +1 -0
  388. package/dist/middleware/oauth-public.js +50 -0
  389. package/dist/middleware/oauth-public.js.map +1 -0
  390. package/dist/middleware/rate-limit.d.ts +182 -0
  391. package/dist/middleware/rate-limit.d.ts.map +1 -0
  392. package/dist/middleware/rate-limit.js +277 -0
  393. package/dist/middleware/rate-limit.js.map +1 -0
  394. package/dist/middleware/request-id.d.ts +10 -0
  395. package/dist/middleware/request-id.d.ts.map +1 -0
  396. package/dist/middleware/request-id.js +42 -0
  397. package/dist/middleware/request-id.js.map +1 -0
  398. package/dist/middleware/scopes.d.ts +33 -0
  399. package/dist/middleware/scopes.d.ts.map +1 -0
  400. package/dist/middleware/scopes.js +139 -0
  401. package/dist/middleware/scopes.js.map +1 -0
  402. package/dist/middleware/security-headers.d.ts +53 -0
  403. package/dist/middleware/security-headers.d.ts.map +1 -0
  404. package/dist/middleware/security-headers.js +96 -0
  405. package/dist/middleware/security-headers.js.map +1 -0
  406. package/dist/observability/index.d.ts +3 -0
  407. package/dist/observability/index.d.ts.map +1 -0
  408. package/dist/observability/index.js +3 -0
  409. package/dist/observability/index.js.map +1 -0
  410. package/dist/observability/metrics.d.ts +17 -0
  411. package/dist/observability/metrics.d.ts.map +1 -0
  412. package/dist/observability/metrics.js +82 -0
  413. package/dist/observability/metrics.js.map +1 -0
  414. package/dist/observability/otel.d.ts +20 -0
  415. package/dist/observability/otel.d.ts.map +1 -0
  416. package/dist/observability/otel.js +54 -0
  417. package/dist/observability/otel.js.map +1 -0
  418. package/dist/pagination.d.ts +57 -0
  419. package/dist/pagination.d.ts.map +1 -0
  420. package/dist/pagination.js +90 -0
  421. package/dist/pagination.js.map +1 -0
  422. package/dist/platform/edition.d.ts +57 -0
  423. package/dist/platform/edition.d.ts.map +1 -0
  424. package/dist/platform/edition.js +90 -0
  425. package/dist/platform/edition.js.map +1 -0
  426. package/dist/platform/entitlements.d.ts +26 -0
  427. package/dist/platform/entitlements.d.ts.map +1 -0
  428. package/dist/platform/entitlements.js +28 -0
  429. package/dist/platform/entitlements.js.map +1 -0
  430. package/dist/platform/events.d.ts +87 -0
  431. package/dist/platform/events.d.ts.map +1 -0
  432. package/dist/platform/events.js +32 -0
  433. package/dist/platform/events.js.map +1 -0
  434. package/dist/platform/index.d.ts +8 -0
  435. package/dist/platform/index.d.ts.map +1 -0
  436. package/dist/platform/index.js +8 -0
  437. package/dist/platform/index.js.map +1 -0
  438. package/dist/platform/local-identity.d.ts +39 -0
  439. package/dist/platform/local-identity.d.ts.map +1 -0
  440. package/dist/platform/local-identity.js +87 -0
  441. package/dist/platform/local-identity.js.map +1 -0
  442. package/dist/platform/registry.d.ts +23 -0
  443. package/dist/platform/registry.d.ts.map +1 -0
  444. package/dist/platform/registry.js +5 -0
  445. package/dist/platform/registry.js.map +1 -0
  446. package/dist/platform/usage.d.ts +11 -0
  447. package/dist/platform/usage.d.ts.map +1 -0
  448. package/dist/platform/usage.js +12 -0
  449. package/dist/platform/usage.js.map +1 -0
  450. package/dist/platform/workspaces.d.ts +25 -0
  451. package/dist/platform/workspaces.d.ts.map +1 -0
  452. package/dist/platform/workspaces.js +44 -0
  453. package/dist/platform/workspaces.js.map +1 -0
  454. package/dist/projects/access.d.ts +40 -0
  455. package/dist/projects/access.d.ts.map +1 -0
  456. package/dist/projects/access.js +133 -0
  457. package/dist/projects/access.js.map +1 -0
  458. package/dist/projects/index.d.ts +2 -0
  459. package/dist/projects/index.d.ts.map +1 -0
  460. package/dist/projects/index.js +2 -0
  461. package/dist/projects/index.js.map +1 -0
  462. package/dist/route-label.d.ts +23 -0
  463. package/dist/route-label.d.ts.map +1 -0
  464. package/dist/route-label.js +29 -0
  465. package/dist/route-label.js.map +1 -0
  466. package/dist/routes/health.d.ts +30 -0
  467. package/dist/routes/health.d.ts.map +1 -0
  468. package/dist/routes/health.js +54 -0
  469. package/dist/routes/health.js.map +1 -0
  470. package/dist/routes/index.d.ts +3 -0
  471. package/dist/routes/index.d.ts.map +1 -0
  472. package/dist/routes/index.js +3 -0
  473. package/dist/routes/index.js.map +1 -0
  474. package/dist/routes/wellknown.d.ts +11 -0
  475. package/dist/routes/wellknown.d.ts.map +1 -0
  476. package/dist/routes/wellknown.js +45 -0
  477. package/dist/routes/wellknown.js.map +1 -0
  478. package/dist/secret.d.ts +30 -0
  479. package/dist/secret.d.ts.map +1 -0
  480. package/dist/secret.js +97 -0
  481. package/dist/secret.js.map +1 -0
  482. package/dist/setup-transport.d.ts +23 -0
  483. package/dist/setup-transport.d.ts.map +1 -0
  484. package/dist/setup-transport.js +52 -0
  485. package/dist/setup-transport.js.map +1 -0
  486. package/dist/state.d.ts +21 -0
  487. package/dist/state.d.ts.map +1 -0
  488. package/dist/state.js +4 -0
  489. package/dist/state.js.map +1 -0
  490. package/dist/storage/driver.d.ts +38 -0
  491. package/dist/storage/driver.d.ts.map +1 -0
  492. package/dist/storage/driver.js +14 -0
  493. package/dist/storage/driver.js.map +1 -0
  494. package/dist/storage/factory.d.ts +4 -0
  495. package/dist/storage/factory.d.ts.map +1 -0
  496. package/dist/storage/factory.js +20 -0
  497. package/dist/storage/factory.js.map +1 -0
  498. package/dist/storage/index.d.ts +4 -0
  499. package/dist/storage/index.d.ts.map +1 -0
  500. package/dist/storage/index.js +4 -0
  501. package/dist/storage/index.js.map +1 -0
  502. package/dist/storage/local.d.ts +21 -0
  503. package/dist/storage/local.d.ts.map +1 -0
  504. package/dist/storage/local.js +88 -0
  505. package/dist/storage/local.js.map +1 -0
  506. package/dist/storage/s3.d.ts +29 -0
  507. package/dist/storage/s3.d.ts.map +1 -0
  508. package/dist/storage/s3.js +82 -0
  509. package/dist/storage/s3.js.map +1 -0
  510. package/dist/testing/fake-hub.d.ts +425 -0
  511. package/dist/testing/fake-hub.d.ts.map +1 -0
  512. package/dist/testing/fake-hub.js +1074 -0
  513. package/dist/testing/fake-hub.js.map +1 -0
  514. package/dist/testing/helpers.d.ts +124 -0
  515. package/dist/testing/helpers.d.ts.map +1 -0
  516. package/dist/testing/helpers.js +174 -0
  517. package/dist/testing/helpers.js.map +1 -0
  518. package/dist/testing/index.d.ts +12 -0
  519. package/dist/testing/index.d.ts.map +1 -0
  520. package/dist/testing/index.js +12 -0
  521. package/dist/testing/index.js.map +1 -0
  522. package/dist/testing/setup-origins.d.ts +21 -0
  523. package/dist/testing/setup-origins.d.ts.map +1 -0
  524. package/dist/testing/setup-origins.js +57 -0
  525. package/dist/testing/setup-origins.js.map +1 -0
  526. package/dist/testing/sso-helpers.d.ts +43 -0
  527. package/dist/testing/sso-helpers.d.ts.map +1 -0
  528. package/dist/testing/sso-helpers.js +159 -0
  529. package/dist/testing/sso-helpers.js.map +1 -0
  530. package/dist/tool-definition.d.ts +382 -0
  531. package/dist/tool-definition.d.ts.map +1 -0
  532. package/dist/tool-definition.js +46 -0
  533. package/dist/tool-definition.js.map +1 -0
  534. package/dist/util/index.d.ts +8 -0
  535. package/dist/util/index.d.ts.map +1 -0
  536. package/dist/util/index.js +8 -0
  537. package/dist/util/index.js.map +1 -0
  538. package/package.json +161 -0
  539. package/src/accounts/deletion.ts +389 -0
  540. package/src/accounts/erasure-log.ts +140 -0
  541. package/src/accounts/index.ts +5 -0
  542. package/src/accounts/mint-refusal.ts +67 -0
  543. package/src/accounts/signup-duplicate.ts +21 -0
  544. package/src/accounts/superadmin.ts +46 -0
  545. package/src/api/apikeys.ts +147 -0
  546. package/src/api/audit.ts +83 -0
  547. package/src/api/break-glass.ts +294 -0
  548. package/src/api/cli-auth.ts +308 -0
  549. package/src/api/create-api.ts +1403 -0
  550. package/src/api/demo-passes.ts +207 -0
  551. package/src/api/errors.ts +13 -0
  552. package/src/api/export.ts +482 -0
  553. package/src/api/files.ts +200 -0
  554. package/src/api/index.ts +29 -0
  555. package/src/api/invitations.ts +396 -0
  556. package/src/api/members.ts +617 -0
  557. package/src/api/onboarding.ts +50 -0
  558. package/src/api/openapi-doc.ts +34 -0
  559. package/src/api/projects.ts +788 -0
  560. package/src/api/scope-routes.ts +12 -0
  561. package/src/api/sso-connect.ts +246 -0
  562. package/src/api/sso-logout.ts +76 -0
  563. package/src/api/teams.ts +575 -0
  564. package/src/api/workspaces.ts +649 -0
  565. package/src/apikeys/index.ts +2 -0
  566. package/src/apikeys/peppers.ts +118 -0
  567. package/src/apikeys/service.ts +223 -0
  568. package/src/app.ts +228 -0
  569. package/src/audit/filters.ts +101 -0
  570. package/src/audit/index.ts +9 -0
  571. package/src/audit/service.ts +154 -0
  572. package/src/boot.ts +953 -0
  573. package/src/constant-time.ts +9 -0
  574. package/src/email/driver.ts +139 -0
  575. package/src/email/index.ts +26 -0
  576. package/src/email/shell.ts +201 -0
  577. package/src/email/templates.ts +184 -0
  578. package/src/entitlements/check.ts +435 -0
  579. package/src/entitlements/clock-skew.ts +58 -0
  580. package/src/entitlements/gate.ts +636 -0
  581. package/src/entitlements/hub-machine-token.ts +205 -0
  582. package/src/entitlements/hub-subject.ts +77 -0
  583. package/src/entitlements/index.ts +37 -0
  584. package/src/entitlements/poster.ts +265 -0
  585. package/src/entitlements/profiles.ts +303 -0
  586. package/src/entitlements/slot.ts +105 -0
  587. package/src/env.ts +456 -0
  588. package/src/files/http.ts +77 -0
  589. package/src/files/index.ts +4 -0
  590. package/src/files/serve.ts +115 -0
  591. package/src/files/service.ts +209 -0
  592. package/src/files/spool.ts +58 -0
  593. package/src/identity/better-auth.ts +1103 -0
  594. package/src/identity/demo-pass-plugin.ts +121 -0
  595. package/src/identity/demo-pass-rules.ts +229 -0
  596. package/src/identity/demo-pass.ts +390 -0
  597. package/src/identity/hub-grant.ts +704 -0
  598. package/src/identity/hub-jwt.ts +78 -0
  599. package/src/identity/hub-live-gate.ts +167 -0
  600. package/src/identity/hub-logout.ts +174 -0
  601. package/src/identity/hub-projection.ts +251 -0
  602. package/src/identity/hub-reconcile.ts +572 -0
  603. package/src/identity/hub-sso.ts +696 -0
  604. package/src/identity/hub-user-client.ts +554 -0
  605. package/src/identity/index.ts +56 -0
  606. package/src/identity/oauth-jwt.ts +128 -0
  607. package/src/identity/resolve-membership.ts +104 -0
  608. package/src/identity/signing-key.ts +164 -0
  609. package/src/index.ts +65 -0
  610. package/src/invitations/index.ts +1 -0
  611. package/src/invitations/service.ts +171 -0
  612. package/src/jobs/index.ts +25 -0
  613. package/src/jobs/pgboss.ts +594 -0
  614. package/src/jobs/timers.ts +287 -0
  615. package/src/logger.ts +67 -0
  616. package/src/mcp/errors.ts +111 -0
  617. package/src/mcp/http.ts +129 -0
  618. package/src/mcp/index.ts +28 -0
  619. package/src/mcp/inputs.ts +33 -0
  620. package/src/mcp/projects.ts +480 -0
  621. package/src/mcp/server.ts +174 -0
  622. package/src/mcp/teams.ts +97 -0
  623. package/src/mcp/tool-kit.ts +148 -0
  624. package/src/members/removal.ts +216 -0
  625. package/src/middleware/auth-body.ts +58 -0
  626. package/src/middleware/auth-context.ts +384 -0
  627. package/src/middleware/body-cap.ts +33 -0
  628. package/src/middleware/body-refusal.ts +23 -0
  629. package/src/middleware/cross-site.ts +122 -0
  630. package/src/middleware/hub-managed.ts +61 -0
  631. package/src/middleware/idempotency.ts +264 -0
  632. package/src/middleware/index.ts +33 -0
  633. package/src/middleware/json-depth.ts +74 -0
  634. package/src/middleware/no-store.ts +30 -0
  635. package/src/middleware/oauth-public.ts +54 -0
  636. package/src/middleware/rate-limit.ts +432 -0
  637. package/src/middleware/request-id.ts +54 -0
  638. package/src/middleware/scopes.ts +150 -0
  639. package/src/middleware/security-headers.ts +129 -0
  640. package/src/observability/index.ts +2 -0
  641. package/src/observability/metrics.ts +102 -0
  642. package/src/observability/otel.ts +79 -0
  643. package/src/pagination.ts +118 -0
  644. package/src/platform/edition.ts +140 -0
  645. package/src/platform/entitlements.ts +47 -0
  646. package/src/platform/events.ts +71 -0
  647. package/src/platform/index.ts +7 -0
  648. package/src/platform/local-identity.ts +90 -0
  649. package/src/platform/registry.ts +28 -0
  650. package/src/platform/usage.ts +13 -0
  651. package/src/platform/workspaces.ts +41 -0
  652. package/src/projects/access.ts +160 -0
  653. package/src/projects/index.ts +7 -0
  654. package/src/route-label.ts +29 -0
  655. package/src/routes/health.ts +79 -0
  656. package/src/routes/index.ts +2 -0
  657. package/src/routes/wellknown.ts +67 -0
  658. package/src/secret.ts +115 -0
  659. package/src/setup-transport.ts +46 -0
  660. package/src/state.ts +23 -0
  661. package/src/storage/driver.ts +48 -0
  662. package/src/storage/factory.ts +34 -0
  663. package/src/storage/index.ts +3 -0
  664. package/src/storage/local.ts +93 -0
  665. package/src/storage/s3.ts +109 -0
  666. package/src/testing/fake-hub.ts +1316 -0
  667. package/src/testing/helpers.ts +254 -0
  668. package/src/testing/index.ts +11 -0
  669. package/src/testing/setup-origins.ts +58 -0
  670. package/src/testing/sso-helpers.ts +178 -0
  671. package/src/tool-definition.ts +463 -0
  672. package/src/util/index.ts +17 -0
  673. package/test/fixtures/onboarding-backfill.sql +13 -0
  674. package/test/fixtures/operator-user-id-backfill.sql +18 -0
  675. package/test/host/dr-lib.sh +253 -0
  676. package/test/host/drizzle/0000_chassis_baseline.sql +438 -0
  677. package/test/host/drizzle/0001_last_owner_guard.sql +42 -0
  678. package/test/host/drizzle/meta/0000_snapshot.json +3566 -0
  679. package/test/host/drizzle/meta/_journal.json +20 -0
  680. package/test/host/drizzle.config.ts +17 -0
  681. package/test/host/identity.ts +41 -0
  682. package/test/host/minimal-host.ts +35 -0
  683. package/test/host/minimal-tool.ts +123 -0
  684. package/test/integration/account-oracle-uniformity.test.ts +284 -0
  685. package/test/integration/account-recovery.test.ts +236 -0
  686. package/test/integration/account.test.ts +120 -0
  687. package/test/integration/api-quota.test.ts +208 -0
  688. package/test/integration/apikey-expiry.test.ts +178 -0
  689. package/test/integration/apikey-pepper-rotation.test.ts +190 -0
  690. package/test/integration/boot-posture.test.ts +169 -0
  691. package/test/integration/break-glass.test.ts +484 -0
  692. package/test/integration/cloud-lifecycle.test.ts +233 -0
  693. package/test/integration/credential-boundaries.test.ts +195 -0
  694. package/test/integration/default-workspace.test.ts +414 -0
  695. package/test/integration/demo-pass-rules.test.ts +332 -0
  696. package/test/integration/demo-pass.test.ts +1222 -0
  697. package/test/integration/dr-verify-real-dump.test.ts +154 -0
  698. package/test/integration/edition.test.ts +868 -0
  699. package/test/integration/email-change.test.ts +394 -0
  700. package/test/integration/empty-tool.test.ts +267 -0
  701. package/test/integration/entitlements-null-hook.test.ts +187 -0
  702. package/test/integration/entitlements.test.ts +693 -0
  703. package/test/integration/export-entries.test.ts +321 -0
  704. package/test/integration/files.test.ts +320 -0
  705. package/test/integration/first-boot-claim.test.ts +131 -0
  706. package/test/integration/gdpr.test.ts +532 -0
  707. package/test/integration/helpers.ts +29 -0
  708. package/test/integration/hub-grant.test.ts +505 -0
  709. package/test/integration/hub-live-gate.test.ts +612 -0
  710. package/test/integration/hub-managed-membership.test.ts +559 -0
  711. package/test/integration/hub-org-selector.test.ts +281 -0
  712. package/test/integration/hub-reconcile.test.ts +646 -0
  713. package/test/integration/hub-sso.test.ts +704 -0
  714. package/test/integration/hub-teams.test.ts +771 -0
  715. package/test/integration/idempotency.test.ts +261 -0
  716. package/test/integration/invite-verification.test.ts +210 -0
  717. package/test/integration/last-owner-race.test.ts +263 -0
  718. package/test/integration/m9-fixes.test.ts +290 -0
  719. package/test/integration/mcp-projects.test.ts +463 -0
  720. package/test/integration/member-removal-race.test.ts +466 -0
  721. package/test/integration/member-removal.test.ts +794 -0
  722. package/test/integration/oauth-mcp.test.ts +477 -0
  723. package/test/integration/oauth-workspace.test.ts +371 -0
  724. package/test/integration/observability.test.ts +183 -0
  725. package/test/integration/onboarding.test.ts +268 -0
  726. package/test/integration/orphan-purge.test.ts +451 -0
  727. package/test/integration/pagination.test.ts +344 -0
  728. package/test/integration/platform-core.test.ts +305 -0
  729. package/test/integration/platform.test.ts +246 -0
  730. package/test/integration/pool-survives-restart.test.ts +80 -0
  731. package/test/integration/projects-cloud.test.ts +193 -0
  732. package/test/integration/projects.test.ts +1310 -0
  733. package/test/integration/security-fixes.test.ts +190 -0
  734. package/test/integration/setup-transport.test.ts +118 -0
  735. package/test/integration/signin-wall.test.ts +103 -0
  736. package/test/integration/signing-key-rotation.test.ts +349 -0
  737. package/test/integration/sso-helpers.ts +15 -0
  738. package/test/integration/sso-logout.test.ts +283 -0
  739. package/test/integration/teams-cloud.test.ts +194 -0
  740. package/test/integration/teams.test.ts +551 -0
  741. package/test/integration/timers.test.ts +377 -0
  742. package/test/integration/two-factor.test.ts +301 -0
  743. package/test/integration/usage-window.test.ts +161 -0
  744. package/test/integration/workspace-create-cloud.test.ts +523 -0
  745. package/test/integration/workspace-create.test.ts +510 -0
  746. package/test/integration/workspace-scoping.test.ts +530 -0
  747. package/test/integration/zz-adv-replay-owner.test.ts +205 -0
  748. package/test/unit/apikey-peppers.test.ts +110 -0
  749. package/test/unit/apikey-prefix.test.ts +34 -0
  750. package/test/unit/audit-filters.test.ts +135 -0
  751. package/test/unit/auth-origins.test.ts +92 -0
  752. package/test/unit/body-cap.test.ts +84 -0
  753. package/test/unit/clock-skew.test.ts +68 -0
  754. package/test/unit/cross-site.test.ts +166 -0
  755. package/test/unit/declared-credits.test.ts +13 -0
  756. package/test/unit/demo-pass-rules.test.ts +192 -0
  757. package/test/unit/email-driver.test.ts +127 -0
  758. package/test/unit/end-pool.test.ts +181 -0
  759. package/test/unit/entitlement-check.test.ts +492 -0
  760. package/test/unit/entitlement-gate.test.ts +1333 -0
  761. package/test/unit/entitlement-profiles.test.ts +289 -0
  762. package/test/unit/erasure-log.test.ts +72 -0
  763. package/test/unit/error-mapping.test.ts +89 -0
  764. package/test/unit/export-entries.test.ts +85 -0
  765. package/test/unit/export-sanitize.test.ts +27 -0
  766. package/test/unit/files-head-route.test.ts +155 -0
  767. package/test/unit/files-http.test.ts +97 -0
  768. package/test/unit/head-rewrite.test.ts +72 -0
  769. package/test/unit/hub-create-org.test.ts +181 -0
  770. package/test/unit/hub-jwt.test.ts +93 -0
  771. package/test/unit/hub-sso-params.test.ts +39 -0
  772. package/test/unit/hub-subject.test.ts +83 -0
  773. package/test/unit/idempotency-crypto.test.ts +45 -0
  774. package/test/unit/json-depth.test.ts +88 -0
  775. package/test/unit/logger-redaction.test.ts +66 -0
  776. package/test/unit/mcp-errors.test.ts +110 -0
  777. package/test/unit/mcp-inputs.test.ts +106 -0
  778. package/test/unit/mcp-project-hints.test.ts +26 -0
  779. package/test/unit/no-store.test.ts +49 -0
  780. package/test/unit/no-tool-migration-filename.test.ts +70 -0
  781. package/test/unit/observability.test.ts +64 -0
  782. package/test/unit/openapi-doc.test.ts +93 -0
  783. package/test/unit/rate-limit-consume-on.test.ts +76 -0
  784. package/test/unit/rate-limit.test.ts +39 -0
  785. package/test/unit/readyz-storage.test.ts +157 -0
  786. package/test/unit/request-quota.test.ts +146 -0
  787. package/test/unit/scopes.test.ts +66 -0
  788. package/test/unit/security-headers.test.ts +131 -0
  789. package/test/unit/serve-content-type.test.ts +74 -0
  790. package/test/unit/setup-transport.test.ts +29 -0
  791. package/test/unit/storage-local.test.ts +53 -0
  792. package/test/unit/superadmin.test.ts +32 -0
  793. package/test/unit/timers.test.ts +287 -0
  794. package/test/unit/tool-definition-guards.test.ts +166 -0
  795. package/test/unit/tool-entitlements-guard.test.ts +168 -0
  796. package/test/unit/usage-poster.test.ts +542 -0
  797. package/test/unit/usage-window.test.ts +48 -0
  798. package/test/unit/workspace-create-audit.test.ts +48 -0
@@ -0,0 +1,480 @@
1
+ import { z } from 'zod';
2
+ import {
3
+ PROJECT_METADATA_MAX_LENGTH,
4
+ projectRoleSchema,
5
+ projectsArchivedFilterSchema
6
+ } from '@antasphere/chassis-contract';
7
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
8
+ import { mcpInputs } from './inputs.js';
9
+ import { deny, jsonText, wrapToolErrors, type ErrorHints, type ToolTextResult } from './errors.js';
10
+ import {
11
+ callApi,
12
+ forWorkspace,
13
+ pageQuery,
14
+ type McpScopes,
15
+ type McpToolContext,
16
+ type ScopeCheck
17
+ } from './tool-kit.js';
18
+ import type { McpIdentity } from './server.js';
19
+
20
+ /**
21
+ * The eleven PROJECT tools, registered by the chassis beside
22
+ * `<toolPrefix>whoami` — a project is a chassis concept (a subgroup of a
23
+ * workspace with its own members and roles), so every tool an instance serves
24
+ * over it is the chassis', not a tool's. Each one is a thin shim over the
25
+ * instance's own /api/v1/projects called IN-PROCESS with the caller's bearer
26
+ * forwarded verbatim: no privileged path, no MCP-only endpoint, and the API's
27
+ * fail-closed scope allowlist plus the tiered project answer (404 before 403
28
+ * before 409) apply unchanged.
29
+ *
30
+ * The conventions of the set are the chassis' (server.ts): reads carry
31
+ * `readOnlyHint: true` and pre-check the read scope, writes describe
32
+ * themselves confirm-first and pre-check the write scope, and every tool
33
+ * takes the same optional `workspace` argument.
34
+ *
35
+ * Nothing here names a tool, a brand or a domain: the prefix arrives as
36
+ * `identity.toolPrefix` and the wire shapes are the contract's.
37
+ */
38
+
39
+ /**
40
+ * What a project IS, in the words an agent that has never seen one needs. It
41
+ * opens every description in the set, so a model reading `tools/list` learns
42
+ * the concept once from whichever tool it looks at first.
43
+ */
44
+ const WHAT_IS_A_PROJECT =
45
+ 'A project is a subgroup of an organization (workspace): a named space with its own members, ' +
46
+ 'used to group work and who may touch it.';
47
+
48
+ /**
49
+ * The three roles, each containing the one before it. Written out wherever a
50
+ * role is chosen or shown, because the whole authorization story of the
51
+ * surface is in it.
52
+ */
53
+ const ROLE_LADDER_BODY =
54
+ '`viewer` reads the project and what is linked to it; `editor` may also write what is linked to ' +
55
+ 'it; `manager` may also rename the project, archive it, and manage its members. An organization ' +
56
+ 'owner or admin acts as a manager on every project.';
57
+ const ROLE_LADDER = `Roles, each containing the one before it: ${ROLE_LADDER_BODY}`;
58
+
59
+ /** How an archived project behaves, and the one way back. */
60
+ const ARCHIVED_RULE =
61
+ 'An archived project is out of the default list and read-only: every change is refused until it ' +
62
+ 'is brought back. A project is never deleted.';
63
+
64
+ /**
65
+ * The project codes, turned from an API code into a sentence a model can act
66
+ * on, for the tool whose prefix is given: a hint that names a tool names it
67
+ * as it is registered (`<toolPrefix>list_project_members`), or the model
68
+ * follows it to a tool that does not exist. Merged into the instance's hint
69
+ * table (`mergeErrorHints`) so a refusal reads as words rather than as a
70
+ * code. The role a refusal needs is the message's, never assumed here: a
71
+ * tool's own route over a project may gate on `editor` where every chassis
72
+ * route gates on `manager`.
73
+ *
74
+ * Every key here is a code only the project routes answer. `not_found` is
75
+ * DELIBERATELY absent: it is the whole instance's code, a tool already words
76
+ * it for its own domain (and its hint wins, `buildMcpServer`), and a sentence
77
+ * about projects on the answer of every other 404 would be worse than none.
78
+ * The tiered answer is stated in the descriptions instead, where it belongs:
79
+ * a project you cannot read answers not found, so being refused is not proof
80
+ * that it exists.
81
+ */
82
+ export function projectErrorHints(toolPrefix: string): ErrorHints {
83
+ const t = (name: string) => `${toolPrefix}${name}`;
84
+ return {
85
+ insufficient_project_role:
86
+ 'Your role on this project is below what this needs (the message names the role; the chassis ' +
87
+ 'routes need manager). Ask a project manager, or an owner or admin of the organization, to make ' +
88
+ 'the change or to raise your role.',
89
+ project_archived:
90
+ 'This project is archived, so it is read-only. Bring it back first (archive the project with ' +
91
+ 'archived set to false), then try again.',
92
+ project_not_archived: 'This project is not archived, so there is nothing to bring back.',
93
+ member_not_found:
94
+ `No such member. On ${t('add_project_member')}: nobody in the organization matches, and a project ` +
95
+ 'member must already be an active organization member, named by the exact user id or email ' +
96
+ `address they joined with. On ${t('set_project_member_role')} or ${t('remove_project_member')}: ` +
97
+ `this person is not on the project (${t('list_project_members')} shows who is).`,
98
+ already_member:
99
+ 'This person or team is already a member of the project — change the role instead of adding ' +
100
+ 'them again.',
101
+ team_not_found:
102
+ `No such team. On ${t('add_project_member')}: no team of the organization has this id ` +
103
+ `(${t('list_teams')} lists them). On ${t('set_project_team_role')} or ${t('remove_project_team')}: ` +
104
+ `this team is not on the project (${t('list_project_members')} shows who is).`,
105
+ guest_target:
106
+ 'This person is an external guest invited to one item: their account is not this organization’s ' +
107
+ 'to put on a project.',
108
+ guest_forbidden:
109
+ 'This credential is a guest of the organization, invited to one item only, and guests take no ' +
110
+ 'part in projects: nothing under the project tools answers it. Use a member’s credential.'
111
+ };
112
+ }
113
+
114
+ /**
115
+ * A project is named by an opaque id, never by its name: two projects may
116
+ * share a name, and the API answers 404 to whoever cannot read one.
117
+ */
118
+ const projectIdInput = z
119
+ .uuid()
120
+ .describe('The project id, from the list or the create answer (never the project name).');
121
+
122
+ const teamIdInput = z
123
+ .uuid()
124
+ .describe('The team id, as the teams list or the project member list reports it (never its name or slug).');
125
+
126
+ const userIdInput = z
127
+ .string()
128
+ .min(1)
129
+ .max(200)
130
+ .describe('The member’s user id, as the member list reports it.');
131
+
132
+ const roleInput = projectRoleSchema.describe(`The role on this project. ${ROLE_LADDER_BODY}`);
133
+
134
+ const nameInput = z.string().min(1).max(200).describe('The project name, as people will read it.');
135
+
136
+ const descriptionInput = z.string().max(2000).describe('A sentence or two on what the project is for.');
137
+
138
+ const metadataInput = z
139
+ .record(z.string(), z.unknown())
140
+ .describe(
141
+ 'Your own structured data on the project, a plain JSON object the server keeps verbatim ' +
142
+ `(at most ${PROJECT_METADATA_MAX_LENGTH} characters once serialized). It REPLACES the whole ` +
143
+ 'object: read the project first and send the merged result, never a fragment.'
144
+ );
145
+
146
+ /**
147
+ * Register the eleven project tools on a server. Called by `buildMcpServer`
148
+ * after `<toolPrefix>whoami` and before the tool's own set, so `tools/list`
149
+ * keeps one stable order: the chassis examples, whoami, the projects, the
150
+ * tool's own.
151
+ */
152
+ export function registerProjectTools(
153
+ server: McpServer,
154
+ ctx: McpToolContext,
155
+ identity: McpIdentity,
156
+ scopes: McpScopes,
157
+ checkScope: ScopeCheck<string>,
158
+ hints: ErrorHints
159
+ ): void {
160
+ const { workspaceInput, cursorInput, limitInput } = mcpInputs(identity);
161
+ const prefix = identity.toolPrefix;
162
+
163
+ /** The read/write pre-check + the per-call workspace seam, in one step. */
164
+ const enter = (
165
+ scope: string,
166
+ workspace: string | undefined
167
+ ): { denied: ToolTextResult } | { ctx: McpToolContext } => {
168
+ const denied = checkScope(ctx.principal, scope);
169
+ return denied ? { denied } : { ctx: forWorkspace(ctx, workspace) };
170
+ };
171
+
172
+ const run = (
173
+ scope: string,
174
+ workspace: string | undefined,
175
+ body: (c: McpToolContext) => Promise<unknown>
176
+ ): Promise<ToolTextResult> => {
177
+ const entered = enter(scope, workspace);
178
+ if ('denied' in entered) return Promise.resolve(entered.denied);
179
+ return wrapToolErrors(async () => jsonText(await body(entered.ctx)), hints);
180
+ };
181
+
182
+ const jsonBody = (value: unknown): RequestInit => ({
183
+ method: 'POST',
184
+ headers: { 'content-type': 'application/json' },
185
+ body: JSON.stringify(value)
186
+ });
187
+
188
+ // ── Reads ────────────────────────────────────────────────────────────────
189
+
190
+ server.registerTool(
191
+ `${prefix}list_projects`,
192
+ {
193
+ description:
194
+ `List the projects you belong to in an organization, newest first. ${WHAT_IS_A_PROJECT} ` +
195
+ `${ROLE_LADDER} Returns { projects: [{ id, name, description, metadata, archivedAt, ` +
196
+ 'createdBy, createdAt, updatedAt, myRole, memberCount }], nextCursor } — `myRole` is YOUR ' +
197
+ 'role on that project, so it tells you in advance what you may do. When nextCursor is ' +
198
+ `non-null, call again with cursor set to it. By default only the live projects are listed; ` +
199
+ `${ARCHIVED_RULE}`,
200
+ inputSchema: {
201
+ workspace: workspaceInput,
202
+ archived: z
203
+ .union([z.boolean(), projectsArchivedFilterSchema])
204
+ .optional()
205
+ .describe(
206
+ 'Which projects to list: false (the default) the live ones, true the archived ones, ' +
207
+ '"all" both.'
208
+ ),
209
+ limit: limitInput,
210
+ cursor: cursorInput
211
+ },
212
+ annotations: { readOnlyHint: true }
213
+ },
214
+ async ({ workspace, archived, limit, cursor }) =>
215
+ run(scopes.read, workspace, (c) =>
216
+ // A model writes the natural boolean; the wire takes the enum.
217
+ callApi(
218
+ c,
219
+ pageQuery(
220
+ '/api/v1/projects',
221
+ { cursor, limit },
222
+ { archived: typeof archived === 'boolean' ? String(archived) : archived }
223
+ )
224
+ )
225
+ )
226
+ );
227
+
228
+ server.registerTool(
229
+ `${prefix}get_project`,
230
+ {
231
+ description:
232
+ `Read one project, with your own role on it. ${WHAT_IS_A_PROJECT} ${ROLE_LADDER} Returns ` +
233
+ '{ id, name, description, metadata, archivedAt, createdBy, createdAt, updatedAt, myRole, ' +
234
+ 'memberCount }. A project you are not a member of answers "not found" whether or not it ' +
235
+ 'exists — being refused is not proof that it is there.',
236
+ inputSchema: { workspace: workspaceInput, projectId: projectIdInput },
237
+ annotations: { readOnlyHint: true }
238
+ },
239
+ async ({ workspace, projectId }) =>
240
+ run(scopes.read, workspace, (c) => callApi(c, `/api/v1/projects/${projectId}`))
241
+ );
242
+
243
+ server.registerTool(
244
+ `${prefix}list_project_members`,
245
+ {
246
+ description:
247
+ `List a project's members and what each of them may do. ${ROLE_LADDER} A member is a ` +
248
+ 'person or a team, told apart by `kind`: a person entry is { kind: "person", userId, email, ' +
249
+ 'name, role, addedBy, createdAt }, a team entry { kind: "team", teamId, slug, name, ' +
250
+ 'membersCount, hubTeamId, role, addedBy, createdAt }, and every member of a team holds the ' +
251
+ 'team’s role; a person’s effective role is the highest of their own entry and their teams’. ' +
252
+ 'Returns { members, nextCursor }; pass a person’s `userId` to the tools that change or remove ' +
253
+ `a member, a team’s \`teamId\` to ${prefix}set_project_team_role and ${prefix}remove_project_team.`,
254
+ inputSchema: {
255
+ workspace: workspaceInput,
256
+ projectId: projectIdInput,
257
+ limit: limitInput,
258
+ cursor: cursorInput
259
+ },
260
+ annotations: { readOnlyHint: true }
261
+ },
262
+ async ({ workspace, projectId, limit, cursor }) =>
263
+ run(scopes.read, workspace, (c) =>
264
+ callApi(c, pageQuery(`/api/v1/projects/${projectId}/members`, { cursor, limit }))
265
+ )
266
+ );
267
+
268
+ // ── Writes ───────────────────────────────────────────────────────────────
269
+
270
+ server.registerTool(
271
+ `${prefix}create_project`,
272
+ {
273
+ description:
274
+ `Create a project in an organization — confirm with the user first (name included). ` +
275
+ `${WHAT_IS_A_PROJECT} You become its first manager, so you may then add members and set ` +
276
+ `their roles. ${ROLE_LADDER} Returns the new project, whose id is what every other ` +
277
+ 'project tool takes.',
278
+ inputSchema: {
279
+ workspace: workspaceInput,
280
+ name: nameInput,
281
+ description: descriptionInput.optional(),
282
+ metadata: metadataInput.optional()
283
+ }
284
+ },
285
+ async ({ workspace, name, description, metadata }) =>
286
+ run(scopes.write, workspace, (c) =>
287
+ callApi(
288
+ c,
289
+ '/api/v1/projects',
290
+ jsonBody({
291
+ name,
292
+ ...(description !== undefined ? { description } : {}),
293
+ ...(metadata !== undefined ? { metadata } : {})
294
+ })
295
+ )
296
+ )
297
+ );
298
+
299
+ server.registerTool(
300
+ `${prefix}update_project`,
301
+ {
302
+ description:
303
+ 'Change a project’s name, description or metadata — confirm with the user first. Needs the ' +
304
+ 'manager role on the project (an organization owner or admin has it everywhere). Send only ' +
305
+ 'the fields you are changing; `metadata` REPLACES the whole object, and a description set to ' +
306
+ `null clears it. ${ARCHIVED_RULE} Returns the project as it now is.`,
307
+ inputSchema: {
308
+ workspace: workspaceInput,
309
+ projectId: projectIdInput,
310
+ name: nameInput.optional(),
311
+ description: descriptionInput
312
+ .nullable()
313
+ .optional()
314
+ .describe('A sentence or two on what the project is for; null clears it.'),
315
+ metadata: metadataInput.optional()
316
+ }
317
+ },
318
+ async ({ workspace, projectId, name, description, metadata }) => {
319
+ if (name === undefined && description === undefined && metadata === undefined) {
320
+ return deny(
321
+ 'Nothing to change: pass at least one of name, description or metadata. ' +
322
+ 'Read the project first if you need its current values.'
323
+ );
324
+ }
325
+ return run(scopes.write, workspace, (c) =>
326
+ callApi(c, `/api/v1/projects/${projectId}`, {
327
+ ...jsonBody({
328
+ ...(name !== undefined ? { name } : {}),
329
+ ...(description !== undefined ? { description } : {}),
330
+ ...(metadata !== undefined ? { metadata } : {})
331
+ }),
332
+ method: 'PATCH'
333
+ })
334
+ );
335
+ }
336
+ );
337
+
338
+ server.registerTool(
339
+ `${prefix}archive_project`,
340
+ {
341
+ description:
342
+ 'Archive a project, or bring an archived one back — confirm with the user first. Needs the ' +
343
+ `manager role on the project. ${ARCHIVED_RULE} Nothing is lost: archiving is reversible, by ` +
344
+ 'calling this same tool with `archived` set to false. Returns the project in its new state.',
345
+ inputSchema: {
346
+ workspace: workspaceInput,
347
+ projectId: projectIdInput,
348
+ archived: z
349
+ .boolean()
350
+ .optional()
351
+ .describe('true (the default) archives the project; false brings an archived one back.')
352
+ }
353
+ // No destructiveHint: a reversible, read-only switch is not a delete,
354
+ // and a host that gates destructive tools must not block the restore.
355
+ },
356
+ async ({ workspace, projectId, archived }) => {
357
+ const leg = archived === false ? 'unarchive' : 'archive';
358
+ return run(scopes.write, workspace, (c) =>
359
+ callApi(c, `/api/v1/projects/${projectId}/${leg}`, { method: 'POST' })
360
+ );
361
+ }
362
+ );
363
+
364
+ server.registerTool(
365
+ `${prefix}add_project_member`,
366
+ {
367
+ description:
368
+ 'Put one of the organization’s own members on a project, with a role — confirm with the ' +
369
+ `user first. Needs the manager role on the project. ${ROLE_LADDER} Name the person by ` +
370
+ 'either `userId` or `email`, and it must be someone who is already an active member of the ' +
371
+ 'organization: this invites nobody and creates no account. Or a team by `teamId` (from ' +
372
+ `${prefix}list_teams), which puts every member of the team on the project with that role. ` +
373
+ 'Exactly one of `userId`, `email` or `teamId`. Returns the new project member, a person or a ' +
374
+ 'team entry.',
375
+ inputSchema: {
376
+ workspace: workspaceInput,
377
+ projectId: projectIdInput,
378
+ userId: userIdInput.optional(),
379
+ email: z.email().optional().describe('The email address the person joined the organization with.'),
380
+ teamId: teamIdInput.optional(),
381
+ role: roleInput
382
+ }
383
+ },
384
+ async ({ workspace, projectId, userId, email, teamId, role }) => {
385
+ if ([userId, email, teamId].filter((k) => k !== undefined).length !== 1) {
386
+ return deny(
387
+ 'Name exactly one member: a person by userId or email, or a team by teamId, not several ' +
388
+ `and not none. The organization member list has both for everyone who has joined; ` +
389
+ `${prefix}list_teams has the team ids.`
390
+ );
391
+ }
392
+ const who = userId !== undefined ? { userId } : email !== undefined ? { email } : { teamId };
393
+ return run(scopes.write, workspace, (c) =>
394
+ callApi(c, `/api/v1/projects/${projectId}/members`, jsonBody({ ...who, role }))
395
+ );
396
+ }
397
+ );
398
+
399
+ server.registerTool(
400
+ `${prefix}set_project_member_role`,
401
+ {
402
+ description:
403
+ 'Change what a project member may do — confirm with the user first. Needs the manager role ' +
404
+ `on the project. ${ROLE_LADDER} Raising someone to manager lets them manage the members and ` +
405
+ 'archive the project too. Returns the member as they now are.',
406
+ inputSchema: {
407
+ workspace: workspaceInput,
408
+ projectId: projectIdInput,
409
+ userId: userIdInput,
410
+ role: roleInput
411
+ }
412
+ },
413
+ async ({ workspace, projectId, userId, role }) =>
414
+ run(scopes.write, workspace, (c) =>
415
+ callApi(c, `/api/v1/projects/${projectId}/members/${encodeURIComponent(userId)}`, {
416
+ ...jsonBody({ role }),
417
+ method: 'PATCH'
418
+ })
419
+ )
420
+ );
421
+
422
+ server.registerTool(
423
+ `${prefix}remove_project_member`,
424
+ {
425
+ description:
426
+ 'Take someone off a project — confirm with the user first; their access to the project and ' +
427
+ 'to what is linked to it stops immediately. Needs the manager role on the project (anyone ' +
428
+ 'may remove themselves). This removes the person from THIS project only: they stay a member ' +
429
+ 'of the organization. Returns a last snapshot of the member that was removed.',
430
+ inputSchema: { workspace: workspaceInput, projectId: projectIdInput, userId: userIdInput },
431
+ annotations: { destructiveHint: true }
432
+ },
433
+ async ({ workspace, projectId, userId }) =>
434
+ run(scopes.write, workspace, (c) =>
435
+ callApi(c, `/api/v1/projects/${projectId}/members/${encodeURIComponent(userId)}`, {
436
+ method: 'DELETE'
437
+ })
438
+ )
439
+ );
440
+
441
+ server.registerTool(
442
+ `${prefix}set_project_team_role`,
443
+ {
444
+ description:
445
+ 'Change the role a team holds on a project — confirm with the user first. Every member of ' +
446
+ `the team holds this role on the project through it. Needs the manager role on the project. ` +
447
+ `${ROLE_LADDER} Returns the team entry as it now is.`,
448
+ inputSchema: {
449
+ workspace: workspaceInput,
450
+ projectId: projectIdInput,
451
+ teamId: teamIdInput,
452
+ role: roleInput
453
+ }
454
+ },
455
+ async ({ workspace, projectId, teamId, role }) =>
456
+ run(scopes.write, workspace, (c) =>
457
+ callApi(c, `/api/v1/projects/${projectId}/teams/${teamId}`, {
458
+ ...jsonBody({ role }),
459
+ method: 'PATCH'
460
+ })
461
+ )
462
+ );
463
+
464
+ server.registerTool(
465
+ `${prefix}remove_project_team`,
466
+ {
467
+ description:
468
+ 'Take a team off a project — confirm with the user first; the access its members held ' +
469
+ 'THROUGH the team stops immediately. Needs the manager role on the project. People who also ' +
470
+ 'have their own entry on the project keep it, and the team itself stays in the organization. ' +
471
+ 'Returns a last snapshot of the team entry that was removed.',
472
+ inputSchema: { workspace: workspaceInput, projectId: projectIdInput, teamId: teamIdInput },
473
+ annotations: { destructiveHint: true }
474
+ },
475
+ async ({ workspace, projectId, teamId }) =>
476
+ run(scopes.write, workspace, (c) =>
477
+ callApi(c, `/api/v1/projects/${projectId}/teams/${teamId}`, { method: 'DELETE' })
478
+ )
479
+ );
480
+ }
@@ -0,0 +1,174 @@
1
+ import type { ToolIdentity } from '@antasphere/chassis-contract';
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { mcpInputs } from './inputs.js';
4
+ import { jsonText, mergeErrorHints, wrapToolErrors, type ErrorHints } from './errors.js';
5
+ import { projectErrorHints, registerProjectTools } from './projects.js';
6
+ import { registerTeamTools } from './teams.js';
7
+ import {
8
+ callApi,
9
+ createScopeCheck,
10
+ forWorkspace,
11
+ pageQuery,
12
+ type McpScopes,
13
+ type McpToolContext
14
+ } from './tool-kit.js';
15
+
16
+ /**
17
+ * The bundled MCP server: tools are thin shims over the instance's own
18
+ * /api/v1 — called IN-PROCESS with the caller's Authorization header
19
+ * forwarded verbatim. MCP is just another API client: no privileged path, no
20
+ * MCP-only endpoints; new behavior lands in the API first. Identity comes
21
+ * from the verified credential, never from a tool parameter.
22
+ *
23
+ * Conventions (ported from the predecessor MCP template):
24
+ * - read tools: `readOnlyHint: true` + a checkScope on the tool's read scope
25
+ * - write tools: confirm-first description + the tool's write scope (+ destructiveHint
26
+ * for deletes) — see the write tools of the tool's own set (its tools.ts)
27
+ * - checkScope is UX only — the API's fail-closed allowlist is the
28
+ * enforcement point; this just gives the model a clean, actionable error.
29
+ *
30
+ * get_me and list_files below are the chassis' original example tools (the
31
+ * end-to-end whoami proof + a cursor-paginated list), followed by
32
+ * `<toolPrefix>whoami`, the identity tool under the tool's own prefix; the product tool set
33
+ * (`<toolPrefix>*`) lives in the tool's app (its tools.ts).
34
+ */
35
+ export type { McpToolContext } from './tool-kit.js';
36
+
37
+ export interface McpServerInfo {
38
+ version: string;
39
+ instanceName: string;
40
+ }
41
+
42
+ /**
43
+ * What a tool plugs into the bundled MCP server: its own tool set (registered
44
+ * AFTER the three chassis tools, so `tools/list` keeps its order), the server
45
+ * instructions, the error hints of its domain codes, and the two scope names
46
+ * the chassis tools pre-check.
47
+ */
48
+ export interface McpToolDefinition {
49
+ registerTools: (server: McpServer, ctx: McpToolContext) => void;
50
+ instructions: (info: McpServerInfo) => string;
51
+ errorHints: ErrorHints;
52
+ scopes: McpScopes;
53
+ }
54
+
55
+ /** The MCP half of the tool's identity (`ToolIdentity['mcp']`): the server's name and the tool names' prefix. */
56
+ export type McpIdentity = ToolIdentity['mcp'];
57
+
58
+ /**
59
+ * The ONE composition of an instance's hint table: the domain hints, then
60
+ * every chassis group (the projects today), then the tool's own last, so a
61
+ * tool may re-word a chassis code and never the reverse. A tool set that
62
+ * wraps its own errors reads the same composition (never a copy), so a
63
+ * chassis group added here reaches the tool's tools without a second edit.
64
+ */
65
+ export function composeErrorHints(toolHints: ErrorHints, toolPrefix: string): ErrorHints {
66
+ return mergeErrorHints({ ...projectErrorHints(toolPrefix), ...toolHints });
67
+ }
68
+
69
+ export function buildMcpServer(
70
+ ctx: McpToolContext,
71
+ info: McpServerInfo,
72
+ tool: McpToolDefinition,
73
+ identity: McpIdentity
74
+ ): McpServer {
75
+ // `<prefix>whoami` (the contract of `toolPrefix`), registered below: the other chassis tools point at it.
76
+ const whoami = `${identity.toolPrefix}whoami`;
77
+ const checkScope = createScopeCheck(tool.scopes);
78
+ const hints = composeErrorHints(tool.errorHints, identity.toolPrefix);
79
+ const server = new McpServer(
80
+ { name: identity.serverName, version: info.version },
81
+ {
82
+ instructions: tool.instructions(info)
83
+ }
84
+ );
85
+
86
+ // The shared inputs (`inputs.ts`): the ones a tool's own set declares its tools with.
87
+ const { workspaceInput, cursorInput, limitInput } = mcpInputs(identity);
88
+
89
+ // ── Pattern 1: READ tool — the end-to-end whoami proof ────────────────────
90
+ server.registerTool(
91
+ 'get_me',
92
+ {
93
+ description:
94
+ 'Who is connected: the user this MCP connection acts as, with all their organizations. ' +
95
+ 'Returns { user: { id, email, name }, workspace, role, via, scopes, workspaces }. ' +
96
+ `Everything done through this server happens as this user. (Alias of ${whoami}.)`,
97
+ inputSchema: { workspace: workspaceInput },
98
+ annotations: { readOnlyHint: true }
99
+ },
100
+ async ({ workspace }) => {
101
+ const denied = checkScope(ctx.principal, tool.scopes.read);
102
+ if (denied) return denied;
103
+ const c = forWorkspace(ctx, workspace);
104
+ return wrapToolErrors(async () => jsonText(await callApi(c, '/api/v1/me')), hints);
105
+ }
106
+ );
107
+
108
+ // ── Pattern 2: LIST tool with cursor pagination passed through ────────────
109
+ server.registerTool(
110
+ 'list_files',
111
+ {
112
+ description:
113
+ "List a workspace's files, newest first. Returns { files: [{ id, sha256, sizeBytes, " +
114
+ 'contentType, originalName, createdBy, createdAt }], nextCursor }. When nextCursor is ' +
115
+ 'non-null, call again with cursor set to it for the next page. Download or upload happen ' +
116
+ 'through the API, not through tools.',
117
+ inputSchema: {
118
+ workspace: workspaceInput,
119
+ limit: limitInput,
120
+ cursor: cursorInput
121
+ },
122
+ annotations: { readOnlyHint: true }
123
+ },
124
+ async ({ workspace, limit, cursor }) => {
125
+ const denied = checkScope(ctx.principal, tool.scopes.read);
126
+ if (denied) return denied;
127
+ const c = forWorkspace(ctx, workspace);
128
+ return wrapToolErrors(
129
+ async () => jsonText(await callApi(c, pageQuery('/api/v1/files', { cursor, limit }))),
130
+ hints
131
+ );
132
+ }
133
+ );
134
+
135
+ // ── Identity under the tool's own prefix ───────────────────────────────────
136
+ // Registered by the chassis (it reads `/me`, nothing of a domain) so that the
137
+ // name every `workspace` argument and `get_me` point at always exists. Third,
138
+ // right before the tool's set: `tools/list` keeps its order.
139
+ server.registerTool(
140
+ whoami,
141
+ {
142
+ description:
143
+ 'Who is connected: the user this MCP connection acts as, plus ALL their organizations ' +
144
+ '(workspaces) with per-entry role/default/suspended flags. Returns { user: { id, email, ' +
145
+ 'name }, workspace, role, via, scopes, workspaces: [...], activeWorkspaceId }. The ' +
146
+ 'credential is the USER; the organization is a PER-CALL parameter: every tool accepts an ' +
147
+ 'optional `workspace` (an id from `workspaces[]`) — omitted, the entry flagged `default: ' +
148
+ 'true` is used (else the oldest membership). Call this first to discover the ids.',
149
+ inputSchema: { workspace: workspaceInput },
150
+ annotations: { readOnlyHint: true }
151
+ },
152
+ async ({ workspace }) => {
153
+ const denied = checkScope(ctx.principal, tool.scopes.read);
154
+ if (denied) return denied;
155
+ const c = forWorkspace(ctx, workspace);
156
+ return wrapToolErrors(async () => jsonText(await callApi(c, '/api/v1/me')), hints);
157
+ }
158
+ );
159
+
160
+ // ── Projects: a chassis concept, so a chassis tool set ─────────────────────
161
+ // A project is a subgroup of a workspace with its own members and roles —
162
+ // the chassis owns it, and therefore owns the eleven tools over it. Registered
163
+ // under the tool's prefix, after whoami and before the tool's own set, so
164
+ // `tools/list` keeps one stable order across every instance.
165
+ registerProjectTools(server, ctx, identity, tool.scopes, checkScope, hints);
166
+ // Teams (PRDCT-2813): a chassis concept too, read-only over MCP, right after
167
+ // the projects they can be members of.
168
+ registerTeamTools(server, ctx, identity, tool.scopes, checkScope, hints);
169
+
170
+ // The product surface: the tool's own set, after the chassis tools.
171
+ tool.registerTools(server, ctx);
172
+
173
+ return server;
174
+ }