@jbctechsolutions/mcp-office365 2.5.1 → 4.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 (369) hide show
  1. package/README.md +66 -57
  2. package/dist/approval/hash.d.ts +8 -8
  3. package/dist/approval/token-manager.d.ts +37 -19
  4. package/dist/approval/token-manager.d.ts.map +1 -1
  5. package/dist/approval/token-manager.js +133 -37
  6. package/dist/approval/token-manager.js.map +1 -1
  7. package/dist/approval/types.d.ts +7 -3
  8. package/dist/approval/types.d.ts.map +1 -1
  9. package/dist/cli.d.ts +21 -0
  10. package/dist/cli.d.ts.map +1 -1
  11. package/dist/cli.js +100 -2
  12. package/dist/cli.js.map +1 -1
  13. package/dist/database/repository.d.ts +48 -48
  14. package/dist/database/repository.d.ts.map +1 -1
  15. package/dist/database/repository.js.map +1 -1
  16. package/dist/delta/mirror.d.ts +67 -0
  17. package/dist/delta/mirror.d.ts.map +1 -0
  18. package/dist/delta/mirror.js +183 -0
  19. package/dist/delta/mirror.js.map +1 -0
  20. package/dist/graph/auth/account-id.d.ts +19 -0
  21. package/dist/graph/auth/account-id.d.ts.map +1 -0
  22. package/dist/graph/auth/account-id.js +55 -0
  23. package/dist/graph/auth/account-id.js.map +1 -0
  24. package/dist/graph/auth/config.d.ts +1 -1
  25. package/dist/graph/auth/config.d.ts.map +1 -1
  26. package/dist/graph/auth/config.js +13 -1
  27. package/dist/graph/auth/config.js.map +1 -1
  28. package/dist/graph/auth/device-code-flow.d.ts +3 -1
  29. package/dist/graph/auth/device-code-flow.d.ts.map +1 -1
  30. package/dist/graph/auth/device-code-flow.js +42 -14
  31. package/dist/graph/auth/device-code-flow.js.map +1 -1
  32. package/dist/graph/auth/index.d.ts +1 -0
  33. package/dist/graph/auth/index.d.ts.map +1 -1
  34. package/dist/graph/auth/index.js +1 -0
  35. package/dist/graph/auth/index.js.map +1 -1
  36. package/dist/graph/auth/token-cache.js +2 -2
  37. package/dist/graph/auth/token-cache.js.map +1 -1
  38. package/dist/graph/client/graph-client.d.ts +141 -8
  39. package/dist/graph/client/graph-client.d.ts.map +1 -1
  40. package/dist/graph/client/graph-client.js +536 -48
  41. package/dist/graph/client/graph-client.js.map +1 -1
  42. package/dist/graph/client/immutable-id-middleware.d.ts +50 -0
  43. package/dist/graph/client/immutable-id-middleware.d.ts.map +1 -0
  44. package/dist/graph/client/immutable-id-middleware.js +137 -0
  45. package/dist/graph/client/immutable-id-middleware.js.map +1 -0
  46. package/dist/graph/content-readers.d.ts +0 -12
  47. package/dist/graph/content-readers.d.ts.map +1 -1
  48. package/dist/graph/content-readers.js +0 -21
  49. package/dist/graph/content-readers.js.map +1 -1
  50. package/dist/graph/index.d.ts +5 -6
  51. package/dist/graph/index.d.ts.map +1 -1
  52. package/dist/graph/index.js +5 -6
  53. package/dist/graph/index.js.map +1 -1
  54. package/dist/graph/mailbox-adapter.d.ts +15 -15
  55. package/dist/graph/mappers/contact-mapper.d.ts +4 -1
  56. package/dist/graph/mappers/contact-mapper.d.ts.map +1 -1
  57. package/dist/graph/mappers/contact-mapper.js +7 -3
  58. package/dist/graph/mappers/contact-mapper.js.map +1 -1
  59. package/dist/graph/mappers/email-mapper.d.ts.map +1 -1
  60. package/dist/graph/mappers/email-mapper.js +7 -4
  61. package/dist/graph/mappers/email-mapper.js.map +1 -1
  62. package/dist/graph/mappers/event-mapper.d.ts.map +1 -1
  63. package/dist/graph/mappers/event-mapper.js +6 -3
  64. package/dist/graph/mappers/event-mapper.js.map +1 -1
  65. package/dist/graph/mappers/folder-mapper.d.ts +0 -4
  66. package/dist/graph/mappers/folder-mapper.d.ts.map +1 -1
  67. package/dist/graph/mappers/folder-mapper.js +9 -19
  68. package/dist/graph/mappers/folder-mapper.js.map +1 -1
  69. package/dist/graph/mappers/index.d.ts +2 -2
  70. package/dist/graph/mappers/index.d.ts.map +1 -1
  71. package/dist/graph/mappers/index.js +2 -2
  72. package/dist/graph/mappers/index.js.map +1 -1
  73. package/dist/graph/mappers/task-mapper.d.ts +4 -2
  74. package/dist/graph/mappers/task-mapper.d.ts.map +1 -1
  75. package/dist/graph/mappers/task-mapper.js +7 -5
  76. package/dist/graph/mappers/task-mapper.js.map +1 -1
  77. package/dist/graph/mappers/utils.d.ts +0 -10
  78. package/dist/graph/mappers/utils.d.ts.map +1 -1
  79. package/dist/graph/mappers/utils.js +0 -19
  80. package/dist/graph/mappers/utils.js.map +1 -1
  81. package/dist/graph/repository.d.ts +409 -276
  82. package/dist/graph/repository.d.ts.map +1 -1
  83. package/dist/graph/repository.js +772 -1082
  84. package/dist/graph/repository.js.map +1 -1
  85. package/dist/ids/mint.d.ts +31 -0
  86. package/dist/ids/mint.d.ts.map +1 -0
  87. package/dist/ids/mint.js +36 -0
  88. package/dist/ids/mint.js.map +1 -0
  89. package/dist/ids/next-action.d.ts +29 -0
  90. package/dist/ids/next-action.d.ts.map +1 -0
  91. package/dist/ids/next-action.js +58 -0
  92. package/dist/ids/next-action.js.map +1 -0
  93. package/dist/ids/resolver.d.ts +31 -0
  94. package/dist/ids/resolver.d.ts.map +1 -0
  95. package/dist/ids/resolver.js +52 -0
  96. package/dist/ids/resolver.js.map +1 -0
  97. package/dist/ids/schema.d.ts +91 -0
  98. package/dist/ids/schema.d.ts.map +1 -0
  99. package/dist/ids/schema.js +131 -0
  100. package/dist/ids/schema.js.map +1 -0
  101. package/dist/ids/token.d.ts +62 -0
  102. package/dist/ids/token.d.ts.map +1 -0
  103. package/dist/ids/token.js +225 -0
  104. package/dist/ids/token.js.map +1 -0
  105. package/dist/index.d.ts +10 -6
  106. package/dist/index.d.ts.map +1 -1
  107. package/dist/index.js +255 -5925
  108. package/dist/index.js.map +1 -1
  109. package/dist/parsers/index.d.ts +0 -1
  110. package/dist/parsers/index.d.ts.map +1 -1
  111. package/dist/parsers/index.js +0 -1
  112. package/dist/parsers/index.js.map +1 -1
  113. package/dist/registry/all-tools.d.ts +14 -0
  114. package/dist/registry/all-tools.d.ts.map +1 -0
  115. package/dist/registry/all-tools.js +68 -0
  116. package/dist/registry/all-tools.js.map +1 -0
  117. package/dist/registry/context.d.ts +19 -0
  118. package/dist/registry/context.d.ts.map +1 -0
  119. package/dist/registry/context.js +20 -0
  120. package/dist/registry/context.js.map +1 -0
  121. package/dist/registry/define-tool.d.ts +15 -0
  122. package/dist/registry/define-tool.d.ts.map +1 -0
  123. package/dist/registry/define-tool.js +8 -0
  124. package/dist/registry/define-tool.js.map +1 -0
  125. package/dist/registry/elicit-links.d.ts +35 -0
  126. package/dist/registry/elicit-links.d.ts.map +1 -0
  127. package/dist/registry/elicit-links.js +102 -0
  128. package/dist/registry/elicit-links.js.map +1 -0
  129. package/dist/registry/elicitor.d.ts +24 -0
  130. package/dist/registry/elicitor.d.ts.map +1 -0
  131. package/dist/registry/elicitor.js +51 -0
  132. package/dist/registry/elicitor.js.map +1 -0
  133. package/dist/registry/index.d.ts +13 -0
  134. package/dist/registry/index.d.ts.map +1 -0
  135. package/dist/registry/index.js +8 -0
  136. package/dist/registry/index.js.map +1 -0
  137. package/dist/registry/registry.d.ts +73 -0
  138. package/dist/registry/registry.d.ts.map +1 -0
  139. package/dist/registry/registry.js +221 -0
  140. package/dist/registry/registry.js.map +1 -0
  141. package/dist/registry/types.d.ts +146 -0
  142. package/dist/registry/types.d.ts.map +1 -0
  143. package/dist/registry/types.js +6 -0
  144. package/dist/registry/types.js.map +1 -0
  145. package/dist/search/compiler.d.ts +49 -0
  146. package/dist/search/compiler.d.ts.map +1 -0
  147. package/dist/search/compiler.js +168 -0
  148. package/dist/search/compiler.js.map +1 -0
  149. package/dist/signature.js +2 -2
  150. package/dist/signature.js.map +1 -1
  151. package/dist/state/delta-store.d.ts +85 -0
  152. package/dist/state/delta-store.d.ts.map +1 -0
  153. package/dist/state/delta-store.js +124 -0
  154. package/dist/state/delta-store.js.map +1 -0
  155. package/dist/state/migrate.d.ts +23 -0
  156. package/dist/state/migrate.d.ts.map +1 -0
  157. package/dist/state/migrate.js +81 -0
  158. package/dist/state/migrate.js.map +1 -0
  159. package/dist/state/schema.d.ts +26 -0
  160. package/dist/state/schema.d.ts.map +1 -0
  161. package/dist/state/schema.js +77 -0
  162. package/dist/state/schema.js.map +1 -0
  163. package/dist/state/store.d.ts +155 -0
  164. package/dist/state/store.d.ts.map +1 -0
  165. package/dist/state/store.js +321 -0
  166. package/dist/state/store.js.map +1 -0
  167. package/dist/tools/calendar-graph.d.ts +41 -0
  168. package/dist/tools/calendar-graph.d.ts.map +1 -0
  169. package/dist/tools/calendar-graph.js +299 -0
  170. package/dist/tools/calendar-graph.js.map +1 -0
  171. package/dist/tools/calendar-permissions.d.ts +17 -7
  172. package/dist/tools/calendar-permissions.d.ts.map +1 -1
  173. package/dist/tools/calendar-permissions.js +60 -4
  174. package/dist/tools/calendar-permissions.js.map +1 -1
  175. package/dist/tools/calendar.d.ts +133 -82
  176. package/dist/tools/calendar.d.ts.map +1 -1
  177. package/dist/tools/calendar.js +249 -136
  178. package/dist/tools/calendar.js.map +1 -1
  179. package/dist/tools/categories.d.ts +14 -4
  180. package/dist/tools/categories.d.ts.map +1 -1
  181. package/dist/tools/categories.js +59 -2
  182. package/dist/tools/categories.js.map +1 -1
  183. package/dist/tools/checklist-items.d.ts +19 -9
  184. package/dist/tools/checklist-items.d.ts.map +1 -1
  185. package/dist/tools/checklist-items.js +71 -5
  186. package/dist/tools/checklist-items.js.map +1 -1
  187. package/dist/tools/contact-folders.d.ts +50 -0
  188. package/dist/tools/contact-folders.d.ts.map +1 -0
  189. package/dist/tools/contact-folders.js +136 -0
  190. package/dist/tools/contact-folders.js.map +1 -0
  191. package/dist/tools/contacts-graph.d.ts +45 -0
  192. package/dist/tools/contacts-graph.d.ts.map +1 -0
  193. package/dist/tools/contacts-graph.js +174 -0
  194. package/dist/tools/contacts-graph.js.map +1 -0
  195. package/dist/tools/contacts.d.ts +61 -30
  196. package/dist/tools/contacts.d.ts.map +1 -1
  197. package/dist/tools/contacts.js +150 -93
  198. package/dist/tools/contacts.js.map +1 -1
  199. package/dist/tools/excel.d.ts +20 -10
  200. package/dist/tools/excel.d.ts.map +1 -1
  201. package/dist/tools/excel.js +82 -6
  202. package/dist/tools/excel.js.map +1 -1
  203. package/dist/tools/focused-overrides.d.ts +14 -4
  204. package/dist/tools/focused-overrides.d.ts.map +1 -1
  205. package/dist/tools/focused-overrides.js +59 -2
  206. package/dist/tools/focused-overrides.js.map +1 -1
  207. package/dist/tools/index.d.ts +4 -5
  208. package/dist/tools/index.d.ts.map +1 -1
  209. package/dist/tools/index.js +4 -6
  210. package/dist/tools/index.js.map +1 -1
  211. package/dist/tools/linked-resources.d.ts +17 -7
  212. package/dist/tools/linked-resources.d.ts.map +1 -1
  213. package/dist/tools/linked-resources.js +60 -4
  214. package/dist/tools/linked-resources.js.map +1 -1
  215. package/dist/tools/mail-graph.d.ts +38 -0
  216. package/dist/tools/mail-graph.d.ts.map +1 -0
  217. package/dist/tools/mail-graph.js +187 -0
  218. package/dist/tools/mail-graph.js.map +1 -0
  219. package/dist/tools/mail-rules.d.ts +20 -8
  220. package/dist/tools/mail-rules.d.ts.map +1 -1
  221. package/dist/tools/mail-rules.js +63 -7
  222. package/dist/tools/mail-rules.js.map +1 -1
  223. package/dist/tools/mail-send.d.ts +39 -27
  224. package/dist/tools/mail-send.d.ts.map +1 -1
  225. package/dist/tools/mail-send.js +249 -24
  226. package/dist/tools/mail-send.js.map +1 -1
  227. package/dist/tools/mail.d.ts +91 -68
  228. package/dist/tools/mail.d.ts.map +1 -1
  229. package/dist/tools/mail.js +232 -243
  230. package/dist/tools/mail.js.map +1 -1
  231. package/dist/tools/mailbox-organization.d.ts +51 -34
  232. package/dist/tools/mailbox-organization.d.ts.map +1 -1
  233. package/dist/tools/mailbox-organization.js +318 -35
  234. package/dist/tools/mailbox-organization.js.map +1 -1
  235. package/dist/tools/mailbox-settings.d.ts +59 -0
  236. package/dist/tools/mailbox-settings.d.ts.map +1 -0
  237. package/dist/tools/mailbox-settings.js +136 -0
  238. package/dist/tools/mailbox-settings.js.map +1 -0
  239. package/dist/tools/meetings.d.ts +24 -14
  240. package/dist/tools/meetings.d.ts.map +1 -1
  241. package/dist/tools/meetings.js +82 -6
  242. package/dist/tools/meetings.js.map +1 -1
  243. package/dist/tools/onedrive.d.ts +26 -16
  244. package/dist/tools/onedrive.d.ts.map +1 -1
  245. package/dist/tools/onedrive.js +140 -11
  246. package/dist/tools/onedrive.js.map +1 -1
  247. package/dist/tools/onenote.d.ts +63 -0
  248. package/dist/tools/onenote.d.ts.map +1 -0
  249. package/dist/tools/onenote.js +221 -0
  250. package/dist/tools/onenote.js.map +1 -0
  251. package/dist/tools/people.d.ts +10 -0
  252. package/dist/tools/people.d.ts.map +1 -1
  253. package/dist/tools/people.js +94 -0
  254. package/dist/tools/people.js.map +1 -1
  255. package/dist/tools/planner-visualization.d.ts +15 -5
  256. package/dist/tools/planner-visualization.d.ts.map +1 -1
  257. package/dist/tools/planner-visualization.js +58 -4
  258. package/dist/tools/planner-visualization.js.map +1 -1
  259. package/dist/tools/planner.d.ts +69 -39
  260. package/dist/tools/planner.d.ts.map +1 -1
  261. package/dist/tools/planner.js +231 -23
  262. package/dist/tools/planner.js.map +1 -1
  263. package/dist/tools/scheduling.d.ts +12 -0
  264. package/dist/tools/scheduling.d.ts.map +1 -1
  265. package/dist/tools/scheduling.js +38 -0
  266. package/dist/tools/scheduling.js.map +1 -1
  267. package/dist/tools/shared-mailbox.d.ts +164 -0
  268. package/dist/tools/shared-mailbox.d.ts.map +1 -0
  269. package/dist/tools/shared-mailbox.js +318 -0
  270. package/dist/tools/shared-mailbox.js.map +1 -0
  271. package/dist/tools/sharepoint-lists.d.ts +131 -0
  272. package/dist/tools/sharepoint-lists.d.ts.map +1 -0
  273. package/dist/tools/sharepoint-lists.js +246 -0
  274. package/dist/tools/sharepoint-lists.js.map +1 -0
  275. package/dist/tools/sharepoint.d.ts +24 -14
  276. package/dist/tools/sharepoint.d.ts.map +1 -1
  277. package/dist/tools/sharepoint.js +85 -9
  278. package/dist/tools/sharepoint.js.map +1 -1
  279. package/dist/tools/task-attachments.d.ts +17 -7
  280. package/dist/tools/task-attachments.d.ts.map +1 -1
  281. package/dist/tools/task-attachments.js +60 -4
  282. package/dist/tools/task-attachments.js.map +1 -1
  283. package/dist/tools/task-lists.d.ts +56 -0
  284. package/dist/tools/task-lists.d.ts.map +1 -0
  285. package/dist/tools/task-lists.js +155 -0
  286. package/dist/tools/task-lists.js.map +1 -0
  287. package/dist/tools/tasks-graph.d.ts +49 -0
  288. package/dist/tools/tasks-graph.d.ts.map +1 -0
  289. package/dist/tools/tasks-graph.js +193 -0
  290. package/dist/tools/tasks-graph.js.map +1 -0
  291. package/dist/tools/tasks.d.ts +121 -29
  292. package/dist/tools/tasks.d.ts.map +1 -1
  293. package/dist/tools/tasks.js +136 -84
  294. package/dist/tools/tasks.js.map +1 -1
  295. package/dist/tools/teams.d.ts +57 -46
  296. package/dist/tools/teams.d.ts.map +1 -1
  297. package/dist/tools/teams.js +288 -26
  298. package/dist/tools/teams.js.map +1 -1
  299. package/dist/tools/what-changed.d.ts +48 -0
  300. package/dist/tools/what-changed.d.ts.map +1 -0
  301. package/dist/tools/what-changed.js +149 -0
  302. package/dist/tools/what-changed.js.map +1 -0
  303. package/dist/types/calendar.d.ts +1 -1
  304. package/dist/types/calendar.d.ts.map +1 -1
  305. package/dist/types/calendar.js.map +1 -1
  306. package/dist/types/contacts.d.ts +1 -1
  307. package/dist/types/contacts.d.ts.map +1 -1
  308. package/dist/types/contacts.js.map +1 -1
  309. package/dist/types/mail.d.ts +1 -1
  310. package/dist/types/mail.d.ts.map +1 -1
  311. package/dist/types/mail.js.map +1 -1
  312. package/dist/utils/errors.d.ts +110 -38
  313. package/dist/utils/errors.d.ts.map +1 -1
  314. package/dist/utils/errors.js +239 -56
  315. package/dist/utils/errors.js.map +1 -1
  316. package/dist/visualization/types.d.ts +4 -4
  317. package/package.json +2 -3
  318. package/dist/applescript/account-repository.d.ts +0 -30
  319. package/dist/applescript/account-repository.d.ts.map +0 -1
  320. package/dist/applescript/account-repository.js +0 -38
  321. package/dist/applescript/account-repository.js.map +0 -1
  322. package/dist/applescript/account-scripts.d.ts +0 -21
  323. package/dist/applescript/account-scripts.d.ts.map +0 -1
  324. package/dist/applescript/account-scripts.js +0 -180
  325. package/dist/applescript/account-scripts.js.map +0 -1
  326. package/dist/applescript/calendar-manager.d.ts +0 -44
  327. package/dist/applescript/calendar-manager.d.ts.map +0 -1
  328. package/dist/applescript/calendar-manager.js +0 -92
  329. package/dist/applescript/calendar-manager.js.map +0 -1
  330. package/dist/applescript/calendar-writer.d.ts +0 -36
  331. package/dist/applescript/calendar-writer.d.ts.map +0 -1
  332. package/dist/applescript/calendar-writer.js +0 -94
  333. package/dist/applescript/calendar-writer.js.map +0 -1
  334. package/dist/applescript/content-readers.d.ts +0 -114
  335. package/dist/applescript/content-readers.d.ts.map +0 -1
  336. package/dist/applescript/content-readers.js +0 -328
  337. package/dist/applescript/content-readers.js.map +0 -1
  338. package/dist/applescript/executor.d.ts +0 -60
  339. package/dist/applescript/executor.d.ts.map +0 -1
  340. package/dist/applescript/executor.js +0 -173
  341. package/dist/applescript/executor.js.map +0 -1
  342. package/dist/applescript/index.d.ts +0 -20
  343. package/dist/applescript/index.d.ts.map +0 -1
  344. package/dist/applescript/index.js +0 -29
  345. package/dist/applescript/index.js.map +0 -1
  346. package/dist/applescript/mail-sender.d.ts +0 -38
  347. package/dist/applescript/mail-sender.d.ts.map +0 -1
  348. package/dist/applescript/mail-sender.js +0 -67
  349. package/dist/applescript/mail-sender.js.map +0 -1
  350. package/dist/applescript/parser.d.ts +0 -235
  351. package/dist/applescript/parser.d.ts.map +0 -1
  352. package/dist/applescript/parser.js +0 -496
  353. package/dist/applescript/parser.js.map +0 -1
  354. package/dist/applescript/repository.d.ts +0 -64
  355. package/dist/applescript/repository.d.ts.map +0 -1
  356. package/dist/applescript/repository.js +0 -444
  357. package/dist/applescript/repository.js.map +0 -1
  358. package/dist/applescript/scripts.d.ts +0 -265
  359. package/dist/applescript/scripts.d.ts.map +0 -1
  360. package/dist/applescript/scripts.js +0 -1483
  361. package/dist/applescript/scripts.js.map +0 -1
  362. package/dist/parsers/olk15.d.ts +0 -87
  363. package/dist/parsers/olk15.d.ts.map +0 -1
  364. package/dist/parsers/olk15.js +0 -368
  365. package/dist/parsers/olk15.js.map +0 -1
  366. package/dist/tools/notes.d.ts +0 -74
  367. package/dist/tools/notes.d.ts.map +0 -1
  368. package/dist/tools/notes.js +0 -136
  369. package/dist/tools/notes.js.map +0 -1
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  MCP server for Microsoft 365 -- mail, calendar, contacts, tasks, teams, people, and planner.
8
8
 
9
- A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that provides **181 tools** for full read/write access to Microsoft 365. Manage your emails, calendar events, contacts, tasks, notes, Teams channels and chats, people directory, and Planner boards directly through MCP.
9
+ A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that provides **229 tools** for full read/write access to Microsoft 365 via the Microsoft Graph API. Manage your emails, calendar events, contacts, tasks, OneNote notes, Teams channels and chats, people directory, and Planner boards directly through MCP.
10
10
 
11
11
  ## Features Overview
12
12
 
@@ -31,15 +31,15 @@ A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that p
31
31
  | Checklist Items | 5 | Subtasks on To Do tasks |
32
32
  | Linked Resources | 4 | Linked resources on To Do tasks |
33
33
  | Task Attachments | 4 | File attachments on To Do tasks |
34
- | Notes (AppleScript only) | 3 | List, read, and search Outlook notes |
34
+ | OneNote | 6 | Browse notebooks/sections/pages, search, and create pages |
35
35
  | Scheduling | 2 | Free/busy availability, meeting time suggestions |
36
36
  | Teams -- Channels | 8 | Channel CRUD, team members |
37
37
  | Teams -- Channel Messages | 6 | Read and send channel messages with replies |
38
38
  | Teams -- Chats | 6 | 1:1 and group chats, send messages |
39
39
  | People & Presence | 8 | People search, org chart, presence status |
40
- | Planner | 17 | Plans, buckets, tasks, task details with ETag |
41
- | Accounts | 1 | List configured Exchange accounts |
42
- | **Total** | **181** | |
40
+ | Planner | 18 | Plans, buckets, tasks, task details with ETag |
41
+ | Shared Mailbox | 8 | Read another user's mailbox, calendar, and OneDrive via delegate/shared access |
42
+ | **Total** | **229** | |
43
43
 
44
44
  ## Quick Start
45
45
 
@@ -49,13 +49,7 @@ A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that p
49
49
  npx -y @jbctechsolutions/mcp-office365
50
50
  ```
51
51
 
52
- By default the server uses the **Microsoft Graph API** backend (cross-platform, full read/write access).
53
-
54
- To use the **AppleScript backend** (classic Outlook for Mac only, limited features), set the environment variable:
55
-
56
- ```bash
57
- USE_APPLESCRIPT=1
58
- ```
52
+ The server connects to Microsoft 365 via the **Microsoft Graph API** (cross-platform, full read/write access).
59
53
 
60
54
  ### Pre-authenticate (optional)
61
55
 
@@ -65,32 +59,49 @@ npx @jbctechsolutions/mcp-office365 auth --status
65
59
  npx @jbctechsolutions/mcp-office365 auth --logout
66
60
  ```
67
61
 
68
- ### Claude Desktop configuration
62
+ ### Server flags
69
63
 
70
- Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
64
+ Pass these when launching the server (after any subcommand) to scope the exposed
65
+ tool surface:
66
+
67
+ | Flag | Effect |
68
+ | --- | --- |
69
+ | `--preset <names>` | Expose only the listed domains (comma-separated). Repeatable. Default (or `all`) exposes the full surface. |
70
+ | `--read-only` | Expose only read tools (`readOnlyHint: true`). All writes, `prepare_*`/`confirm_*`, and destructive tools are hidden; calling one returns a `READ_ONLY_MODE` error. Note: `download_*` and `get_*_photo` tools are excluded too — they write fetched bytes to local disk and so are not read-only. |
71
+ | `--confirm <mode>` | How a destructive `prepare_*` seeks confirmation. `token` (default) returns an approval token to pass to the matching `confirm_*` tool. `elicit` asks the user inline (MCP elicitation, ~60s) and, on approval, executes immediately; if the client can't elicit, the user cancels, or it times out, it falls back to the token flow. An explicit decline cancels and invalidates the token. |
72
+
73
+ Valid presets: `mail`, `calendar`, `contacts`, `tasks`, `notes`, `teams`,
74
+ `planner`, `files`, `sharepoint`, `excel`, `people`, `meetings`, `shared` (plus `all`).
75
+ An unknown preset name fails startup with the valid list.
76
+
77
+ ```bash
78
+ # Mail + calendar only, read-only
79
+ npx @jbctechsolutions/mcp-office365 --preset mail,calendar --read-only
80
+ ```
81
+
82
+ In a client config, add them to `args`:
71
83
 
72
- **Graph API backend (default):**
73
84
  ```json
74
85
  {
75
86
  "mcpServers": {
76
87
  "office365": {
77
88
  "command": "npx",
78
- "args": ["-y", "@jbctechsolutions/mcp-office365"]
89
+ "args": ["-y", "@jbctechsolutions/mcp-office365", "--preset", "mail,calendar", "--read-only"]
79
90
  }
80
91
  }
81
92
  }
82
93
  ```
83
94
 
84
- **AppleScript backend** (macOS + classic Outlook only):
95
+ ### Claude Desktop configuration
96
+
97
+ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
98
+
85
99
  ```json
86
100
  {
87
101
  "mcpServers": {
88
102
  "office365": {
89
103
  "command": "npx",
90
- "args": ["-y", "@jbctechsolutions/mcp-office365"],
91
- "env": {
92
- "USE_APPLESCRIPT": "1"
93
- }
104
+ "args": ["-y", "@jbctechsolutions/mcp-office365"]
94
105
  }
95
106
  }
96
107
  }
@@ -171,16 +182,7 @@ For production, work accounts with conditional access, or full control over the
171
182
 
172
183
  ## Tool Reference
173
184
 
174
- All 181 tools listed below. Tools marked *(Graph API)* require `USE_GRAPH_API=1`. Tools marked *(AppleScript only)* are not available with Graph API.
175
-
176
- <details>
177
- <summary><strong>Accounts (1)</strong></summary>
178
-
179
- | Tool | Description |
180
- |------|-------------|
181
- | `list_accounts` | List all Exchange accounts configured in Outlook |
182
-
183
- </details>
185
+ All 229 tools listed below.
184
186
 
185
187
  <details>
186
188
  <summary><strong>Mail -- Reading (9)</strong></summary>
@@ -455,15 +457,16 @@ All 181 tools listed below. Tools marked *(Graph API)* require `USE_GRAPH_API=1`
455
457
  </details>
456
458
 
457
459
  <details>
458
- <summary><strong>Notes (3)</strong> <em>(AppleScript only)</em></summary>
460
+ <summary><strong>OneNote (6)</strong> <em>(Graph API)</em></summary>
459
461
 
460
462
  | Tool | Description |
461
463
  |------|-------------|
462
- | `list_notes` | List notes with pagination |
463
- | `get_note` | Get note details |
464
- | `search_notes` | Search notes by content |
465
-
466
- > Notes are only available with the AppleScript backend. Microsoft Graph API does not provide access to Outlook Notes.
464
+ | `list_notebooks` | List OneNote notebooks for the current user |
465
+ | `list_note_sections` | List OneNote sections, optionally scoped to a notebook |
466
+ | `list_note_pages` | List OneNote pages, optionally scoped to a section |
467
+ | `get_note_page` | Get a OneNote page's metadata and HTML content |
468
+ | `search_note_pages` | Search OneNote pages by keyword |
469
+ | `create_note_page` | Create a new OneNote page in a section |
467
470
 
468
471
  </details>
469
472
 
@@ -548,7 +551,7 @@ All 181 tools listed below. Tools marked *(Graph API)* require `USE_GRAPH_API=1`
548
551
  </details>
549
552
 
550
553
  <details>
551
- <summary><strong>Planner (17)</strong> <em>(Graph API)</em></summary>
554
+ <summary><strong>Planner (18)</strong> <em>(Graph API)</em></summary>
552
555
 
553
556
  | Tool | Description |
554
557
  |------|-------------|
@@ -562,6 +565,7 @@ All 181 tools listed below. Tools marked *(Graph API)* require `USE_GRAPH_API=1`
562
565
  | `prepare_delete_bucket` | Prepare to delete a Planner bucket (two-phase) |
563
566
  | `confirm_delete_bucket` | Confirm Planner bucket deletion |
564
567
  | `list_planner_tasks` | List all tasks in a Planner plan |
568
+ | `list_my_planner_tasks` | List all Planner tasks assigned to the signed-in user across every plan |
565
569
  | `get_planner_task` | Get details for a specific Planner task |
566
570
  | `create_planner_task` | Create a new task in a Planner plan |
567
571
  | `update_planner_task` | Update a Planner task |
@@ -572,14 +576,27 @@ All 181 tools listed below. Tools marked *(Graph API)* require `USE_GRAPH_API=1`
572
576
 
573
577
  </details>
574
578
 
575
- ## Architecture
579
+ <details>
580
+ <summary><strong>Shared Mailbox (8)</strong> <em>(Graph API)</em></summary>
576
581
 
577
- ### Dual Backend
582
+ Read another user's mailbox, calendar, or OneDrive via `/users/{upn}/...`, relying on the signed-in user having delegate/shared access (`Mail.Read.Shared` / `Calendars.Read.Shared` / `Files.Read.All`). Read-only. These return **raw Graph ids** (not durable tokens, which are scoped to your own `/me` mailbox); pass the `mailbox` plus the raw id back to the matching `get_*` tool.
578
583
 
579
- The server supports two backends:
584
+ | Tool | Description |
585
+ | --- | --- |
586
+ | `list_shared_mailbox_folders` | List mail folders in a shared/delegated mailbox |
587
+ | `list_shared_mailbox_emails` | List emails in a shared/delegated mailbox (optionally by folder) |
588
+ | `get_shared_mailbox_email` | Get a single email from a shared/delegated mailbox by raw Graph id |
589
+ | `search_shared_mailbox_emails` | Full-text search a shared/delegated mailbox |
590
+ | `list_shared_calendar_events` | List events from another user's calendar (optionally within a window) |
591
+ | `get_shared_calendar_event` | Get a single event from another user's calendar by raw Graph id |
592
+ | `list_shared_user_drive_items` | List items in another user's OneDrive (root or a folder) |
593
+ | `search_shared_user_drive_items` | Search another user's OneDrive |
580
594
 
581
- - **Microsoft Graph API (default)** -- connects to Microsoft 365 cloud services. Full read/write across all 181 tools. No Outlook installation required. Works on macOS, Windows, and Linux.
582
- - **AppleScript** (`USE_APPLESCRIPT=1`) -- communicates with classic Outlook for Mac via `osascript`. Works offline, no Microsoft account needed. Limited to reading mail, calendar, contacts, tasks, and notes, plus calendar write operations and email sending.
595
+ </details>
596
+
597
+ ## Architecture
598
+
599
+ The server connects to Microsoft 365 cloud services via the **Microsoft Graph API**. Full read/write access across all 229 tools. No Outlook installation required. Works on macOS, Windows, and Linux.
583
600
 
584
601
  ### Two-Phase Approval
585
602
 
@@ -587,7 +604,7 @@ Destructive operations (delete, send, move, forward, etc.) use a prepare/confirm
587
604
 
588
605
  ### ID Caching
589
606
 
590
- The server maintains an internal ID mapping layer. AppleScript and Graph API use different ID formats; the caching layer assigns stable numeric IDs so tool callers do not need to track backend-specific identifiers.
607
+ The server maintains an internal ID mapping layer that assigns stable, durable identifier tokens for Graph API resources so tool callers do not need to track raw Graph object IDs.
591
608
 
592
609
  ### ETag Caching
593
610
 
@@ -597,8 +614,7 @@ Planner resources use ETag-based concurrency control. The server caches ETags fr
597
614
 
598
615
  ```
599
616
  src/
600
- applescript/ AppleScript integration (legacy backend)
601
- graph/ Microsoft Graph API integration (default)
617
+ graph/ Microsoft Graph API integration
602
618
  auth/ MSAL authentication, device code flow, token cache
603
619
  client/ Graph client wrapper with response caching
604
620
  mappers/ Graph-to-internal type mappers
@@ -609,7 +625,7 @@ src/
609
625
 
610
626
  ## Required Graph API Permissions
611
627
 
612
- These delegated permissions are requested when using the Graph API backend:
628
+ These delegated permissions are requested via Microsoft Graph:
613
629
 
614
630
  | Permission | Purpose |
615
631
  |------------|---------|
@@ -629,24 +645,17 @@ These delegated permissions are requested when using the Graph API backend:
629
645
  | `User.ReadBasic.All` | Read basic user profiles and photos |
630
646
  | `Presence.Read.All` | Read user presence/availability |
631
647
  | `Group.Read.All` | Read Microsoft 365 groups (for Planner) |
648
+ | `Mail.Read.Shared` | Read mail in shared/delegated mailboxes |
649
+ | `Calendars.Read.Shared` | Read shared/delegated calendars |
650
+ | `Files.Read.All` | Read another user's OneDrive files (shared/delegate access) |
632
651
 
633
652
  ## Environment Variables
634
653
 
635
654
  | Variable | Description | Default |
636
655
  |----------|-------------|---------|
637
- | `USE_APPLESCRIPT` | Set to `1` or `true` for legacy AppleScript backend | (unset -- uses Graph API) |
638
656
  | `OUTLOOK_MCP_CLIENT_ID` | Override the embedded Azure AD client ID | (embedded) |
639
657
  | `OUTLOOK_MCP_TENANT_ID` | Azure AD tenant ID | `common` |
640
658
 
641
- ## Known Limitations
642
-
643
- **AppleScript backend:**
644
- - Google accounts in Outlook are not accessible (macOS/Outlook limitation). Use IMAP configuration or the Graph API backend instead.
645
- - Write operations limited to calendar events and email sending. All other writes require Graph API.
646
-
647
- **Graph API backend:**
648
- - Outlook Notes are not available (Graph API does not expose them). Use AppleScript backend for notes.
649
-
650
659
  ## Contributing
651
660
 
652
661
  We welcome contributions. Please see our [Contributing Guide](CONTRIBUTING.md) for details.
@@ -7,9 +7,9 @@
7
7
  * Used to detect if the email changed between prepare and confirm.
8
8
  */
9
9
  export declare function hashEmailForApproval(email: {
10
- id: number;
10
+ id: string;
11
11
  subject: string | null;
12
- folderId: number;
12
+ folderId: string;
13
13
  timeReceived: number | null;
14
14
  }): string;
15
15
  /**
@@ -17,7 +17,7 @@ export declare function hashEmailForApproval(email: {
17
17
  * Used to detect if the folder changed between prepare and confirm.
18
18
  */
19
19
  export declare function hashFolderForApproval(folder: {
20
- id: number;
20
+ id: string;
21
21
  name: string | null;
22
22
  messageCount: number;
23
23
  }): string;
@@ -26,7 +26,7 @@ export declare function hashFolderForApproval(folder: {
26
26
  * Used to detect if the draft changed between prepare and confirm.
27
27
  */
28
28
  export declare function hashDraftForSend(draft: {
29
- id: number;
29
+ id: string;
30
30
  subject: string | null;
31
31
  recipientCount: number;
32
32
  }): string;
@@ -45,7 +45,7 @@ export declare function hashDirectSendForApproval(params: {
45
45
  * Captures the original message ID, comment length, and reply-all flag.
46
46
  */
47
47
  export declare function hashReplyForApproval(params: {
48
- originalId: number;
48
+ originalId: string;
49
49
  commentLength: number;
50
50
  replyAll: boolean;
51
51
  }): string;
@@ -54,7 +54,7 @@ export declare function hashReplyForApproval(params: {
54
54
  * Captures the original message ID and the number of forward recipients.
55
55
  */
56
56
  export declare function hashForwardForApproval(params: {
57
- originalId: number;
57
+ originalId: string;
58
58
  recipientCount: number;
59
59
  }): string;
60
60
  /**
@@ -62,7 +62,7 @@ export declare function hashForwardForApproval(params: {
62
62
  * Used to detect if the event changed between prepare and confirm.
63
63
  */
64
64
  export declare function hashEventForApproval(event: {
65
- id: number;
65
+ id: string;
66
66
  subject: string | null;
67
67
  startDateTime: string | null;
68
68
  }): string;
@@ -71,7 +71,7 @@ export declare function hashEventForApproval(event: {
71
71
  * Used to detect if the contact changed between prepare and confirm.
72
72
  */
73
73
  export declare function hashContactForApproval(contact: {
74
- id: number;
74
+ id: string;
75
75
  displayName: string | null;
76
76
  emailAddress: string | null;
77
77
  }): string;
@@ -2,49 +2,67 @@
2
2
  * Copyright (c) 2026 JBC Tech Solutions, LLC
3
3
  * Licensed under the MIT License. See LICENSE file in the project root.
4
4
  */
5
+ import type { StateStore } from '../state/store.js';
5
6
  import type { OperationType, TargetType, ApprovalToken, ValidationResult } from './types.js';
6
- /**
7
- * Manages approval tokens for destructive operations.
8
- *
9
- * Tokens are stored in memory and are single-use. They expire
10
- * after a configurable TTL (default 5 minutes).
11
- */
7
+ /** Options for {@link ApprovalTokenManager}. */
8
+ export interface ApprovalTokenManagerOptions {
9
+ /** Token lifetime (default 24h). */
10
+ ttlMs?: number;
11
+ /** Durable store; omit for in-memory (tests / degraded mode). */
12
+ store?: StateStore;
13
+ /**
14
+ * Account stamp for stored tokens (D7). May be a function, since the signed-in
15
+ * account (MSAL `homeAccountId`) is only known after auth — later than when
16
+ * this manager is constructed — and is resolved lazily at each token op.
17
+ */
18
+ accountId?: string | (() => string);
19
+ /** Clock, for deterministic tests. */
20
+ now?: () => number;
21
+ }
12
22
  export declare class ApprovalTokenManager {
13
23
  private readonly tokens;
14
24
  private readonly ttlMs;
15
- constructor(ttlMs?: number);
25
+ private readonly store;
26
+ private readonly resolveAccountId;
27
+ private readonly now;
28
+ constructor(options?: ApprovalTokenManagerOptions | number);
29
+ /** The account scope for store ops, resolved fresh each call (D7). */
30
+ private get accountId();
16
31
  /**
17
32
  * Generates a new approval token for a destructive operation.
18
33
  */
19
34
  generateToken(params: {
20
35
  operation: OperationType;
21
36
  targetType: TargetType;
22
- targetId: number;
37
+ targetId: string;
23
38
  targetHash: string;
24
39
  metadata?: Record<string, unknown>;
25
40
  }): ApprovalToken;
26
41
  /**
27
- * Looks up a token by ID without consuming or validating it.
28
- * Returns undefined if the token does not exist.
42
+ * Looks up a token by ID without consuming or validating it. Returns undefined
43
+ * if the token does not exist (or belongs to another account, when durable).
29
44
  */
30
45
  lookupToken(tokenId: string): ApprovalToken | undefined;
31
46
  /**
32
- * Validates a token without consuming it or modifying state.
33
- * Checks existence, expiry, operation match, and target match.
47
+ * Validates a token without consuming it. Checks existence, prior redemption,
48
+ * expiry, operation match, and target match.
34
49
  */
35
- validateToken(tokenId: string, operation: OperationType, targetId: number): ValidationResult;
50
+ validateToken(tokenId: string, operation: OperationType, targetId: string): ValidationResult;
51
+ private check;
36
52
  /**
37
- * Validates and consumes a token (one-time use).
38
- * On success, the token is removed from the store.
53
+ * Validates and consumes a token (one-time use). Durable stores use an atomic
54
+ * guarded consume so only one caller across processes sharing the db — can
55
+ * redeem it; a losing/repeat caller gets `ALREADY_CONSUMED` (D8).
39
56
  */
40
- consumeToken(tokenId: string, operation: OperationType, targetId: number): ValidationResult;
57
+ consumeToken(tokenId: string, operation: OperationType, targetId: string): ValidationResult;
41
58
  /**
42
- * Removes all expired tokens from the store.
59
+ * Removes expired tokens from the in-memory store. Durable stores purge on
60
+ * boot (90-day retention), so this is a no-op there.
43
61
  */
44
62
  cleanupExpiredTokens(): void;
45
63
  /**
46
- * Returns the number of active (non-expired) tokens.
47
- * Useful for testing and monitoring.
64
+ * Number of active in-memory tokens (testing/monitoring). Durable tokens are
65
+ * not counted here they live in the store.
48
66
  */
49
67
  get size(): number;
50
68
  }
@@ -1 +1 @@
1
- {"version":3,"file":"token-manager.d.ts","sourceRoot":"","sources":["../../src/approval/token-manager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAa7F;;;;;GAKG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoC;IAC3D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;gBAEnB,KAAK,GAAE,MAAuB;IAI1C;;OAEG;IACH,aAAa,CAAC,MAAM,EAAE;QACpB,SAAS,EAAE,aAAa,CAAC;QACzB,UAAU,EAAE,UAAU,CAAC;QACvB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACpC,GAAG,aAAa;IAsBjB;;;OAGG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAIvD;;;OAGG;IACH,aAAa,CACX,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,aAAa,EACxB,QAAQ,EAAE,MAAM,GACf,gBAAgB;IAsBnB;;;OAGG;IACH,YAAY,CACV,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,aAAa,EACxB,QAAQ,EAAE,MAAM,GACf,gBAAgB;IAUnB;;OAEG;IACH,oBAAoB,IAAI,IAAI;IAS5B;;;OAGG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
1
+ {"version":3,"file":"token-manager.d.ts","sourceRoot":"","sources":["../../src/approval/token-manager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAeH,OAAO,KAAK,EAAE,UAAU,EAAoB,MAAM,mBAAmB,CAAC;AACtE,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAa7F,gDAAgD;AAChD,MAAM,WAAW,2BAA2B;IAC1C,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IACpC,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoC;IAC3D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAyB;IAC/C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAe;IAChD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;gBAEvB,OAAO,GAAE,2BAA2B,GAAG,MAAW;IAU9D,sEAAsE;IACtE,OAAO,KAAK,SAAS,GAEpB;IAED;;OAEG;IACH,aAAa,CAAC,MAAM,EAAE;QACpB,SAAS,EAAE,aAAa,CAAC;QACzB,UAAU,EAAE,UAAU,CAAC;QACvB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACpC,GAAG,aAAa;IAsCjB;;;OAGG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAQvD;;;OAGG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,GAAG,gBAAgB;IAyB5F,OAAO,CAAC,KAAK;IAeb;;;;OAIG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,GAAG,gBAAgB;IA4B3F;;;OAGG;IACH,oBAAoB,IAAI,IAAI;IAY5B;;;OAGG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
@@ -3,41 +3,43 @@
3
3
  * Licensed under the MIT License. See LICENSE file in the project root.
4
4
  */
5
5
  /**
6
- * Approval token manager.
6
+ * Approval token manager (U9). Manages the lifecycle of two-phase approval
7
+ * tokens: generation, validation, and atomic single-use consumption.
7
8
  *
8
- * Manages the lifecycle of approval tokens: generation, validation,
9
- * consumption (one-time use), and expiry cleanup.
9
+ * When a durable {@link StateStore} is supplied (production), tokens persist to
10
+ * SQLite with a 24h TTL and are consumed via an atomic guarded write (D8), so an
11
+ * approval prepared in one process/session survives a restart and can be
12
+ * redeemed exactly once — even across concurrent Claude Code windows. Without a
13
+ * store (tests / degraded mode) it falls back to an in-memory map, preserving
14
+ * the original behavior and public surface.
10
15
  */
11
16
  import { randomUUID } from 'node:crypto';
12
- // =============================================================================
13
- // Constants
14
- // =============================================================================
15
- const DEFAULT_TTL_MS = 5 * 60 * 1000; // 5 minutes
17
+ const DEFAULT_TTL_MS = 24 * 60 * 60 * 1000; // 24h (D8, up from 5 minutes)
16
18
  const CLEANUP_THRESHOLD = 100;
17
- // =============================================================================
18
- // Token Manager
19
- // =============================================================================
20
- /**
21
- * Manages approval tokens for destructive operations.
22
- *
23
- * Tokens are stored in memory and are single-use. They expire
24
- * after a configurable TTL (default 5 minutes).
25
- */
26
19
  export class ApprovalTokenManager {
27
20
  tokens = new Map();
28
21
  ttlMs;
29
- constructor(ttlMs = DEFAULT_TTL_MS) {
30
- this.ttlMs = ttlMs;
22
+ store;
23
+ resolveAccountId;
24
+ now;
25
+ constructor(options = {}) {
26
+ // Back-compat: some call sites/tests pass a bare ttlMs number.
27
+ const opts = typeof options === 'number' ? { ttlMs: options } : options;
28
+ this.ttlMs = opts.ttlMs ?? DEFAULT_TTL_MS;
29
+ this.store = opts.store;
30
+ const account = opts.accountId ?? 'default';
31
+ this.resolveAccountId = typeof account === 'function' ? account : (() => account);
32
+ this.now = opts.now ?? (() => Date.now());
33
+ }
34
+ /** The account scope for store ops, resolved fresh each call (D7). */
35
+ get accountId() {
36
+ return this.resolveAccountId();
31
37
  }
32
38
  /**
33
39
  * Generates a new approval token for a destructive operation.
34
40
  */
35
41
  generateToken(params) {
36
- // Clean up expired tokens if the map is getting large
37
- if (this.tokens.size > CLEANUP_THRESHOLD) {
38
- this.cleanupExpiredTokens();
39
- }
40
- const now = Date.now();
42
+ const now = this.now();
41
43
  const token = {
42
44
  tokenId: randomUUID(),
43
45
  operation: params.operation,
@@ -48,26 +50,73 @@ export class ApprovalTokenManager {
48
50
  expiresAt: now + this.ttlMs,
49
51
  metadata: Object.freeze({ ...params.metadata }),
50
52
  };
51
- this.tokens.set(token.tokenId, token);
53
+ if (this.store != null) {
54
+ const target = {
55
+ targetType: token.targetType,
56
+ targetId: token.targetId,
57
+ targetHash: token.targetHash,
58
+ metadata: { ...token.metadata },
59
+ };
60
+ this.store.putApprovalToken({
61
+ token: token.tokenId,
62
+ action: token.operation,
63
+ targetJson: JSON.stringify(target),
64
+ contentHash: token.targetHash,
65
+ accountId: this.accountId,
66
+ expiresAt: token.expiresAt,
67
+ createdAt: token.createdAt,
68
+ });
69
+ }
70
+ else {
71
+ if (this.tokens.size > CLEANUP_THRESHOLD) {
72
+ this.cleanupExpiredTokens();
73
+ }
74
+ this.tokens.set(token.tokenId, token);
75
+ }
52
76
  return token;
53
77
  }
54
78
  /**
55
- * Looks up a token by ID without consuming or validating it.
56
- * Returns undefined if the token does not exist.
79
+ * Looks up a token by ID without consuming or validating it. Returns undefined
80
+ * if the token does not exist (or belongs to another account, when durable).
57
81
  */
58
82
  lookupToken(tokenId) {
83
+ if (this.store != null) {
84
+ const row = this.store.getApprovalToken(tokenId, this.accountId);
85
+ return row != null ? (rowToToken(row) ?? undefined) : undefined;
86
+ }
59
87
  return this.tokens.get(tokenId);
60
88
  }
61
89
  /**
62
- * Validates a token without consuming it or modifying state.
63
- * Checks existence, expiry, operation match, and target match.
90
+ * Validates a token without consuming it. Checks existence, prior redemption,
91
+ * expiry, operation match, and target match.
64
92
  */
65
93
  validateToken(tokenId, operation, targetId) {
94
+ if (this.store != null) {
95
+ const row = this.store.getApprovalToken(tokenId, this.accountId);
96
+ if (row == null) {
97
+ return { valid: false, error: 'NOT_FOUND' };
98
+ }
99
+ if (row.redeemedAt != null) {
100
+ return { valid: false, error: 'ALREADY_CONSUMED' };
101
+ }
102
+ const token = rowToToken(row);
103
+ // A corrupt/tampered target_json fails closed as NOT_FOUND rather than
104
+ // throwing out of validate — the token simply can't be redeemed.
105
+ if (token == null) {
106
+ return { valid: false, error: 'NOT_FOUND' };
107
+ }
108
+ return this.check(token, operation, targetId);
109
+ }
66
110
  const token = this.tokens.get(tokenId);
67
111
  if (token == null) {
68
112
  return { valid: false, error: 'NOT_FOUND' };
69
113
  }
70
- if (Date.now() > token.expiresAt) {
114
+ return this.check(token, operation, targetId);
115
+ }
116
+ check(token, operation, targetId) {
117
+ // `>=` so validate agrees with the store's consume guard (expires_at > now):
118
+ // a token is expired at the exact expiry instant, on both paths.
119
+ if (this.now() >= token.expiresAt) {
71
120
  return { valid: false, error: 'EXPIRED' };
72
121
  }
73
122
  if (token.operation !== operation) {
@@ -79,21 +128,44 @@ export class ApprovalTokenManager {
79
128
  return { valid: true, token };
80
129
  }
81
130
  /**
82
- * Validates and consumes a token (one-time use).
83
- * On success, the token is removed from the store.
131
+ * Validates and consumes a token (one-time use). Durable stores use an atomic
132
+ * guarded consume so only one caller across processes sharing the db — can
133
+ * redeem it; a losing/repeat caller gets `ALREADY_CONSUMED` (D8).
84
134
  */
85
135
  consumeToken(tokenId, operation, targetId) {
86
136
  const result = this.validateToken(tokenId, operation, targetId);
87
- if (result.valid) {
88
- this.tokens.delete(tokenId);
137
+ if (!result.valid) {
138
+ return result;
139
+ }
140
+ if (this.store != null) {
141
+ const consumed = this.store.consumeApprovalToken({
142
+ token: tokenId,
143
+ accountId: this.accountId,
144
+ now: this.now(),
145
+ });
146
+ switch (consumed.status) {
147
+ case 'consumed':
148
+ return result;
149
+ case 'already_redeemed':
150
+ return { valid: false, error: 'ALREADY_CONSUMED' };
151
+ case 'expired':
152
+ return { valid: false, error: 'EXPIRED' };
153
+ default:
154
+ return { valid: false, error: 'NOT_FOUND' };
155
+ }
89
156
  }
157
+ this.tokens.delete(tokenId);
90
158
  return result;
91
159
  }
92
160
  /**
93
- * Removes all expired tokens from the store.
161
+ * Removes expired tokens from the in-memory store. Durable stores purge on
162
+ * boot (90-day retention), so this is a no-op there.
94
163
  */
95
164
  cleanupExpiredTokens() {
96
- const now = Date.now();
165
+ if (this.store != null) {
166
+ return;
167
+ }
168
+ const now = this.now();
97
169
  for (const [tokenId, token] of this.tokens) {
98
170
  if (now > token.expiresAt) {
99
171
  this.tokens.delete(tokenId);
@@ -101,11 +173,35 @@ export class ApprovalTokenManager {
101
173
  }
102
174
  }
103
175
  /**
104
- * Returns the number of active (non-expired) tokens.
105
- * Useful for testing and monitoring.
176
+ * Number of active in-memory tokens (testing/monitoring). Durable tokens are
177
+ * not counted here they live in the store.
106
178
  */
107
179
  get size() {
108
180
  return this.tokens.size;
109
181
  }
110
182
  }
183
+ /** Reconstructs an {@link ApprovalToken} from a stored row, or null if the
184
+ * persisted target JSON is corrupt/unparseable (fail closed). */
185
+ function rowToToken(row) {
186
+ let target;
187
+ try {
188
+ target = JSON.parse(row.targetJson);
189
+ }
190
+ catch {
191
+ return null;
192
+ }
193
+ return {
194
+ tokenId: row.token,
195
+ operation: row.action,
196
+ targetType: target.targetType,
197
+ // Coerce to string: a token persisted by a pre-v4 build may carry a numeric
198
+ // targetId (e.g. the send_email/upload_file sentinel `0`), which would else
199
+ // fail the strict `!==` target check against v4's string ids within the TTL.
200
+ targetId: String(target.targetId),
201
+ targetHash: target.targetHash ?? row.contentHash ?? '',
202
+ createdAt: row.createdAt,
203
+ expiresAt: row.expiresAt,
204
+ metadata: Object.freeze({ ...target.metadata }),
205
+ };
206
+ }
111
207
  //# sourceMappingURL=token-manager.js.map