@dobbyai/mcp-external 1.0.4 → 1.2.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 (315) hide show
  1. package/README.md +44 -14
  2. package/dist/__tests__/agent-mail-tools.test.d.ts +8 -0
  3. package/dist/__tests__/agent-mail-tools.test.d.ts.map +1 -0
  4. package/dist/__tests__/agent-mail-tools.test.js +255 -0
  5. package/dist/__tests__/agent-mail-tools.test.js.map +1 -0
  6. package/dist/__tests__/annotations.test.d.ts +8 -0
  7. package/dist/__tests__/annotations.test.d.ts.map +1 -0
  8. package/dist/__tests__/annotations.test.js +108 -0
  9. package/dist/__tests__/annotations.test.js.map +1 -0
  10. package/dist/__tests__/auth.test.d.ts +7 -0
  11. package/dist/__tests__/auth.test.d.ts.map +1 -0
  12. package/dist/__tests__/auth.test.js +161 -0
  13. package/dist/__tests__/auth.test.js.map +1 -0
  14. package/dist/__tests__/doctor.test.d.ts +16 -0
  15. package/dist/__tests__/doctor.test.d.ts.map +1 -0
  16. package/dist/__tests__/doctor.test.js +258 -0
  17. package/dist/__tests__/doctor.test.js.map +1 -0
  18. package/dist/__tests__/external-agents-tools.test.d.ts +11 -0
  19. package/dist/__tests__/external-agents-tools.test.d.ts.map +1 -0
  20. package/dist/__tests__/external-agents-tools.test.js +619 -0
  21. package/dist/__tests__/external-agents-tools.test.js.map +1 -0
  22. package/dist/__tests__/gateway-bearer.test.d.ts +12 -0
  23. package/dist/__tests__/gateway-bearer.test.d.ts.map +1 -0
  24. package/dist/__tests__/gateway-bearer.test.js +112 -0
  25. package/dist/__tests__/gateway-bearer.test.js.map +1 -0
  26. package/dist/__tests__/gateway-key-resolver.test.d.ts +10 -0
  27. package/dist/__tests__/gateway-key-resolver.test.d.ts.map +1 -0
  28. package/dist/__tests__/gateway-key-resolver.test.js +125 -0
  29. package/dist/__tests__/gateway-key-resolver.test.js.map +1 -0
  30. package/dist/__tests__/http-concurrency.test.d.ts +20 -0
  31. package/dist/__tests__/http-concurrency.test.d.ts.map +1 -0
  32. package/dist/__tests__/http-concurrency.test.js +254 -0
  33. package/dist/__tests__/http-concurrency.test.js.map +1 -0
  34. package/dist/__tests__/integration/protocol.test.d.ts +8 -0
  35. package/dist/__tests__/integration/protocol.test.d.ts.map +1 -0
  36. package/dist/__tests__/integration/protocol.test.js +110 -0
  37. package/dist/__tests__/integration/protocol.test.js.map +1 -0
  38. package/dist/__tests__/mcp-integrations.test.d.ts +8 -0
  39. package/dist/__tests__/mcp-integrations.test.d.ts.map +1 -0
  40. package/dist/__tests__/mcp-integrations.test.js +365 -0
  41. package/dist/__tests__/mcp-integrations.test.js.map +1 -0
  42. package/dist/__tests__/memory-graph-tools.test.d.ts +8 -0
  43. package/dist/__tests__/memory-graph-tools.test.d.ts.map +1 -0
  44. package/dist/__tests__/memory-graph-tools.test.js +254 -0
  45. package/dist/__tests__/memory-graph-tools.test.js.map +1 -0
  46. package/dist/__tests__/registry-dispatch.test.d.ts +11 -0
  47. package/dist/__tests__/registry-dispatch.test.d.ts.map +1 -0
  48. package/dist/__tests__/registry-dispatch.test.js +30 -0
  49. package/dist/__tests__/registry-dispatch.test.js.map +1 -0
  50. package/dist/__tests__/registry-listing-parity.test.d.ts +2 -0
  51. package/dist/__tests__/registry-listing-parity.test.d.ts.map +1 -0
  52. package/dist/__tests__/registry-listing-parity.test.js +89 -0
  53. package/dist/__tests__/registry-listing-parity.test.js.map +1 -0
  54. package/dist/__tests__/role-cap.test.d.ts +2 -0
  55. package/dist/__tests__/role-cap.test.d.ts.map +1 -0
  56. package/dist/__tests__/role-cap.test.js +113 -0
  57. package/dist/__tests__/role-cap.test.js.map +1 -0
  58. package/dist/__tests__/schedule-tools.test.d.ts +8 -0
  59. package/dist/__tests__/schedule-tools.test.d.ts.map +1 -0
  60. package/dist/__tests__/schedule-tools.test.js +285 -0
  61. package/dist/__tests__/schedule-tools.test.js.map +1 -0
  62. package/dist/__tests__/server-gateway-key.test.d.ts +18 -0
  63. package/dist/__tests__/server-gateway-key.test.d.ts.map +1 -0
  64. package/dist/__tests__/server-gateway-key.test.js +148 -0
  65. package/dist/__tests__/server-gateway-key.test.js.map +1 -0
  66. package/dist/__tests__/server-user-scoped.test.d.ts +34 -0
  67. package/dist/__tests__/server-user-scoped.test.d.ts.map +1 -0
  68. package/dist/__tests__/server-user-scoped.test.js +577 -0
  69. package/dist/__tests__/server-user-scoped.test.js.map +1 -0
  70. package/dist/__tests__/task-id-pattern.test.d.ts +12 -0
  71. package/dist/__tests__/task-id-pattern.test.d.ts.map +1 -0
  72. package/dist/__tests__/task-id-pattern.test.js +43 -0
  73. package/dist/__tests__/task-id-pattern.test.js.map +1 -0
  74. package/dist/__tests__/tiers.test.d.ts +7 -0
  75. package/dist/__tests__/tiers.test.d.ts.map +1 -0
  76. package/dist/__tests__/tiers.test.js +199 -0
  77. package/dist/__tests__/tiers.test.js.map +1 -0
  78. package/dist/__tests__/tools/hosted-agents.test.d.ts +9 -0
  79. package/dist/__tests__/tools/hosted-agents.test.d.ts.map +1 -0
  80. package/dist/__tests__/tools/hosted-agents.test.js +301 -0
  81. package/dist/__tests__/tools/hosted-agents.test.js.map +1 -0
  82. package/dist/__tests__/tools/llm-providers.test.d.ts +10 -0
  83. package/dist/__tests__/tools/llm-providers.test.d.ts.map +1 -0
  84. package/dist/__tests__/tools/llm-providers.test.js +105 -0
  85. package/dist/__tests__/tools/llm-providers.test.js.map +1 -0
  86. package/dist/__tests__/tools/services.test.js +139 -98
  87. package/dist/__tests__/tools/services.test.js.map +1 -1
  88. package/dist/__tests__/tools.test.d.ts +7 -0
  89. package/dist/__tests__/tools.test.d.ts.map +1 -0
  90. package/dist/__tests__/tools.test.js +152 -0
  91. package/dist/__tests__/tools.test.js.map +1 -0
  92. package/dist/__tests__/transport.test.d.ts +7 -0
  93. package/dist/__tests__/transport.test.d.ts.map +1 -0
  94. package/dist/__tests__/transport.test.js +397 -0
  95. package/dist/__tests__/transport.test.js.map +1 -0
  96. package/dist/__tests__/validate-credentials.test.d.ts +9 -0
  97. package/dist/__tests__/validate-credentials.test.d.ts.map +1 -0
  98. package/dist/__tests__/validate-credentials.test.js +172 -0
  99. package/dist/__tests__/validate-credentials.test.js.map +1 -0
  100. package/dist/__tests__/web-eval-tools.test.d.ts +8 -0
  101. package/dist/__tests__/web-eval-tools.test.d.ts.map +1 -0
  102. package/dist/__tests__/web-eval-tools.test.js +241 -0
  103. package/dist/__tests__/web-eval-tools.test.js.map +1 -0
  104. package/dist/__tests__/whoami.test.d.ts +11 -0
  105. package/dist/__tests__/whoami.test.d.ts.map +1 -0
  106. package/dist/__tests__/whoami.test.js +194 -0
  107. package/dist/__tests__/whoami.test.js.map +1 -0
  108. package/dist/__tests__/workflow-tools.test.d.ts +8 -0
  109. package/dist/__tests__/workflow-tools.test.d.ts.map +1 -0
  110. package/dist/__tests__/workflow-tools.test.js +261 -0
  111. package/dist/__tests__/workflow-tools.test.js.map +1 -0
  112. package/dist/__tests__/workloads.test.d.ts +9 -0
  113. package/dist/__tests__/workloads.test.d.ts.map +1 -0
  114. package/dist/__tests__/workloads.test.js +169 -0
  115. package/dist/__tests__/workloads.test.js.map +1 -0
  116. package/dist/auth/oauth-provider.d.ts +34 -0
  117. package/dist/auth/oauth-provider.d.ts.map +1 -0
  118. package/dist/auth/oauth-provider.js +75 -0
  119. package/dist/auth/oauth-provider.js.map +1 -0
  120. package/dist/auth/token-verifier.d.ts +45 -0
  121. package/dist/auth/token-verifier.d.ts.map +1 -0
  122. package/dist/auth/token-verifier.js +160 -0
  123. package/dist/auth/token-verifier.js.map +1 -0
  124. package/dist/connectors/claude-desktop.d.ts.map +1 -1
  125. package/dist/connectors/claude-desktop.js +3 -2
  126. package/dist/connectors/claude-desktop.js.map +1 -1
  127. package/dist/connectors/cursor.d.ts.map +1 -1
  128. package/dist/connectors/cursor.js +3 -2
  129. package/dist/connectors/cursor.js.map +1 -1
  130. package/dist/connectors/setup.d.ts.map +1 -1
  131. package/dist/connectors/setup.js +2 -1
  132. package/dist/connectors/setup.js.map +1 -1
  133. package/dist/connectors/vscode.d.ts.map +1 -1
  134. package/dist/connectors/vscode.js +3 -2
  135. package/dist/connectors/vscode.js.map +1 -1
  136. package/dist/connectors/windsurf.d.ts.map +1 -1
  137. package/dist/connectors/windsurf.js +3 -2
  138. package/dist/connectors/windsurf.js.map +1 -1
  139. package/dist/doctor.d.ts +34 -0
  140. package/dist/doctor.d.ts.map +1 -0
  141. package/dist/doctor.js +134 -0
  142. package/dist/doctor.js.map +1 -0
  143. package/dist/http-server.d.ts +56 -0
  144. package/dist/http-server.d.ts.map +1 -0
  145. package/dist/http-server.js +455 -0
  146. package/dist/http-server.js.map +1 -0
  147. package/dist/index.d.ts +5 -1
  148. package/dist/index.d.ts.map +1 -1
  149. package/dist/index.js +96 -171
  150. package/dist/index.js.map +1 -1
  151. package/dist/lib/consts.d.ts +21 -0
  152. package/dist/lib/consts.d.ts.map +1 -0
  153. package/dist/lib/consts.js +30 -0
  154. package/dist/lib/consts.js.map +1 -0
  155. package/dist/lib/dobby-client.d.ts +60 -3
  156. package/dist/lib/dobby-client.d.ts.map +1 -1
  157. package/dist/lib/dobby-client.js +145 -44
  158. package/dist/lib/dobby-client.js.map +1 -1
  159. package/dist/lib/gateway-key-resolver.d.ts +38 -0
  160. package/dist/lib/gateway-key-resolver.d.ts.map +1 -0
  161. package/dist/lib/gateway-key-resolver.js +59 -0
  162. package/dist/lib/gateway-key-resolver.js.map +1 -0
  163. package/dist/lib/log.d.ts +25 -0
  164. package/dist/lib/log.d.ts.map +1 -0
  165. package/dist/lib/log.js +36 -0
  166. package/dist/lib/log.js.map +1 -0
  167. package/dist/server.d.ts +175 -0
  168. package/dist/server.d.ts.map +1 -0
  169. package/dist/server.js +1017 -0
  170. package/dist/server.js.map +1 -0
  171. package/dist/tools/agent-mail.d.ts +112 -0
  172. package/dist/tools/agent-mail.d.ts.map +1 -0
  173. package/dist/tools/agent-mail.js +118 -0
  174. package/dist/tools/agent-mail.js.map +1 -0
  175. package/dist/tools/agent-versions.d.ts +93 -0
  176. package/dist/tools/agent-versions.d.ts.map +1 -0
  177. package/dist/tools/agent-versions.js +99 -0
  178. package/dist/tools/agent-versions.js.map +1 -0
  179. package/dist/tools/approvals.d.ts +24 -34
  180. package/dist/tools/approvals.d.ts.map +1 -1
  181. package/dist/tools/approvals.js +24 -81
  182. package/dist/tools/approvals.js.map +1 -1
  183. package/dist/tools/claude-code-sync.d.ts +40 -0
  184. package/dist/tools/claude-code-sync.d.ts.map +1 -0
  185. package/dist/tools/claude-code-sync.js +52 -0
  186. package/dist/tools/claude-code-sync.js.map +1 -0
  187. package/dist/tools/control-plane.d.ts +118 -0
  188. package/dist/tools/control-plane.d.ts.map +1 -0
  189. package/dist/tools/control-plane.js +135 -0
  190. package/dist/tools/control-plane.js.map +1 -0
  191. package/dist/tools/crew-builder.d.ts +24 -66
  192. package/dist/tools/crew-builder.d.ts.map +1 -1
  193. package/dist/tools/crew-builder.js +24 -185
  194. package/dist/tools/crew-builder.js.map +1 -1
  195. package/dist/tools/crewai.d.ts +24 -63
  196. package/dist/tools/crewai.d.ts.map +1 -1
  197. package/dist/tools/crewai.js +24 -145
  198. package/dist/tools/crewai.js.map +1 -1
  199. package/dist/tools/exa.d.ts +126 -0
  200. package/dist/tools/exa.d.ts.map +1 -0
  201. package/dist/tools/exa.js +125 -0
  202. package/dist/tools/exa.js.map +1 -0
  203. package/dist/tools/external-agents.d.ts +440 -0
  204. package/dist/tools/external-agents.d.ts.map +1 -0
  205. package/dist/tools/external-agents.js +386 -0
  206. package/dist/tools/external-agents.js.map +1 -0
  207. package/dist/tools/github-mcp.d.ts +228 -0
  208. package/dist/tools/github-mcp.d.ts.map +1 -0
  209. package/dist/tools/github-mcp.js +235 -0
  210. package/dist/tools/github-mcp.js.map +1 -0
  211. package/dist/tools/governance.d.ts +273 -0
  212. package/dist/tools/governance.d.ts.map +1 -0
  213. package/dist/tools/governance.js +286 -0
  214. package/dist/tools/governance.js.map +1 -0
  215. package/dist/tools/hosted-agents.d.ts +216 -0
  216. package/dist/tools/hosted-agents.d.ts.map +1 -0
  217. package/dist/tools/hosted-agents.js +214 -0
  218. package/dist/tools/hosted-agents.js.map +1 -0
  219. package/dist/tools/index.d.ts +6335 -191
  220. package/dist/tools/index.d.ts.map +1 -1
  221. package/dist/tools/index.js +441 -172
  222. package/dist/tools/index.js.map +1 -1
  223. package/dist/tools/jira.d.ts +60 -176
  224. package/dist/tools/jira.d.ts.map +1 -1
  225. package/dist/tools/jira.js +60 -365
  226. package/dist/tools/jira.js.map +1 -1
  227. package/dist/tools/llm-providers.d.ts +50 -0
  228. package/dist/tools/llm-providers.d.ts.map +1 -0
  229. package/dist/tools/llm-providers.js +41 -0
  230. package/dist/tools/llm-providers.js.map +1 -0
  231. package/dist/tools/mcp-metrics.d.ts +47 -0
  232. package/dist/tools/mcp-metrics.d.ts.map +1 -0
  233. package/dist/tools/mcp-metrics.js +53 -0
  234. package/dist/tools/mcp-metrics.js.map +1 -0
  235. package/dist/tools/mcp-tools.d.ts +12 -29
  236. package/dist/tools/mcp-tools.d.ts.map +1 -1
  237. package/dist/tools/mcp-tools.js +12 -131
  238. package/dist/tools/mcp-tools.js.map +1 -1
  239. package/dist/tools/mem0.d.ts +127 -0
  240. package/dist/tools/mem0.d.ts.map +1 -0
  241. package/dist/tools/mem0.js +155 -0
  242. package/dist/tools/mem0.js.map +1 -0
  243. package/dist/tools/memory-graph.d.ts +151 -0
  244. package/dist/tools/memory-graph.d.ts.map +1 -0
  245. package/dist/tools/memory-graph.js +159 -0
  246. package/dist/tools/memory-graph.js.map +1 -0
  247. package/dist/tools/memory-stores.d.ts +141 -0
  248. package/dist/tools/memory-stores.d.ts.map +1 -0
  249. package/dist/tools/memory-stores.js +147 -0
  250. package/dist/tools/memory-stores.js.map +1 -0
  251. package/dist/tools/messages.d.ts +12 -20
  252. package/dist/tools/messages.d.ts.map +1 -1
  253. package/dist/tools/messages.js +12 -49
  254. package/dist/tools/messages.js.map +1 -1
  255. package/dist/tools/moltbook.d.ts +328 -0
  256. package/dist/tools/moltbook.d.ts.map +1 -0
  257. package/dist/tools/moltbook.js +334 -0
  258. package/dist/tools/moltbook.js.map +1 -0
  259. package/dist/tools/monitoring-attribution.d.ts +71 -0
  260. package/dist/tools/monitoring-attribution.d.ts.map +1 -0
  261. package/dist/tools/monitoring-attribution.js +74 -0
  262. package/dist/tools/monitoring-attribution.js.map +1 -0
  263. package/dist/tools/ops.d.ts +139 -0
  264. package/dist/tools/ops.d.ts.map +1 -0
  265. package/dist/tools/ops.js +151 -0
  266. package/dist/tools/ops.js.map +1 -0
  267. package/dist/tools/orchestrations.d.ts +109 -0
  268. package/dist/tools/orchestrations.d.ts.map +1 -0
  269. package/dist/tools/orchestrations.js +115 -0
  270. package/dist/tools/orchestrations.js.map +1 -0
  271. package/dist/tools/outcomes.d.ts +138 -0
  272. package/dist/tools/outcomes.d.ts.map +1 -0
  273. package/dist/tools/outcomes.js +136 -0
  274. package/dist/tools/outcomes.js.map +1 -0
  275. package/dist/tools/schedules.d.ts +149 -0
  276. package/dist/tools/schedules.d.ts.map +1 -0
  277. package/dist/tools/schedules.js +155 -0
  278. package/dist/tools/schedules.js.map +1 -0
  279. package/dist/tools/services.d.ts +6 -16
  280. package/dist/tools/services.d.ts.map +1 -1
  281. package/dist/tools/services.js +6 -135
  282. package/dist/tools/services.js.map +1 -1
  283. package/dist/tools/sessions.d.ts +124 -0
  284. package/dist/tools/sessions.d.ts.map +1 -0
  285. package/dist/tools/sessions.js +130 -0
  286. package/dist/tools/sessions.js.map +1 -0
  287. package/dist/tools/setup-status.d.ts +29 -0
  288. package/dist/tools/setup-status.d.ts.map +1 -0
  289. package/dist/tools/setup-status.js +35 -0
  290. package/dist/tools/setup-status.js.map +1 -0
  291. package/dist/tools/tasks.d.ts +44 -56
  292. package/dist/tools/tasks.d.ts.map +1 -1
  293. package/dist/tools/tasks.js +48 -212
  294. package/dist/tools/tasks.js.map +1 -1
  295. package/dist/tools/tiers.d.ts +55 -0
  296. package/dist/tools/tiers.d.ts.map +1 -0
  297. package/dist/tools/tiers.js +239 -0
  298. package/dist/tools/tiers.js.map +1 -0
  299. package/dist/tools/unified-agents.d.ts +43 -0
  300. package/dist/tools/unified-agents.d.ts.map +1 -0
  301. package/dist/tools/unified-agents.js +46 -0
  302. package/dist/tools/unified-agents.js.map +1 -0
  303. package/dist/tools/web-eval.d.ts +129 -0
  304. package/dist/tools/web-eval.d.ts.map +1 -0
  305. package/dist/tools/web-eval.js +136 -0
  306. package/dist/tools/web-eval.js.map +1 -0
  307. package/dist/tools/workflow.d.ts +105 -0
  308. package/dist/tools/workflow.d.ts.map +1 -0
  309. package/dist/tools/workflow.js +111 -0
  310. package/dist/tools/workflow.js.map +1 -0
  311. package/dist/tools/workloads.d.ts +81 -0
  312. package/dist/tools/workloads.d.ts.map +1 -0
  313. package/dist/tools/workloads.js +81 -0
  314. package/dist/tools/workloads.js.map +1 -0
  315. package/package.json +13 -7
@@ -0,0 +1,285 @@
1
+ /**
2
+ * Schedule MCP Tools Tests
3
+ *
4
+ * Tests for scheduled agent task execution:
5
+ * create_schedule, list_schedules, pause_schedule, delete_schedule
6
+ */
7
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
8
+ import { createRegistry, toMcpResult } from '@dobbyai/capability-core';
9
+ // Mock DobbyClient
10
+ const mockClient = {
11
+ apiUrl: 'http://localhost:3000',
12
+ apiKey: 'test-api-key',
13
+ createSchedule: vi.fn(),
14
+ listSchedules: vi.fn(),
15
+ pauseSchedule: vi.fn(),
16
+ deleteSchedule: vi.fn(),
17
+ };
18
+ // ADR-019: the legacy handle* functions are gone — dispatch goes through the
19
+ // capability registry (handlers are verbatim copies; MCP output byte-identical).
20
+ const registry = createRegistry();
21
+ const callCap = async (id, client, args) => toMcpResult(await registry.get(id).handler({ client: client }, args));
22
+ // ============================================
23
+ // Create Schedule
24
+ // ============================================
25
+ describe('Schedule: Create Schedule', () => {
26
+ beforeEach(() => {
27
+ vi.resetAllMocks();
28
+ });
29
+ it('creates a daily recurring schedule', async () => {
30
+ mockClient.createSchedule.mockResolvedValueOnce({
31
+ schedule: {
32
+ id: 'sched_abc123',
33
+ name: 'Daily code review',
34
+ scheduleType: 'recurring',
35
+ scheduleDescription: 'Daily at 09:00',
36
+ nextRunAt: '2026-03-06T09:00:00.000Z',
37
+ overlapPolicy: 'skip',
38
+ taskTitle: 'Review pending PRs',
39
+ },
40
+ });
41
+ const result = await callCap('create_schedule', mockClient, {
42
+ name: 'Daily code review',
43
+ task_title: 'Review pending PRs',
44
+ task_description: 'Review all open pull requests and provide feedback',
45
+ schedule_type: 'recurring',
46
+ frequency: 'daily',
47
+ time: '09:00',
48
+ timezone: 'Asia/Jerusalem',
49
+ });
50
+ expect(mockClient.createSchedule).toHaveBeenCalledOnce();
51
+ expect(result.content[0].text).toContain('Schedule created successfully');
52
+ expect(result.content[0].text).toContain('sched_abc123');
53
+ expect(result.content[0].text).toContain('Daily at 09:00');
54
+ });
55
+ it('creates a weekly recurring schedule', async () => {
56
+ mockClient.createSchedule.mockResolvedValueOnce({
57
+ schedule: {
58
+ id: 'sched_def456',
59
+ name: 'Weekly security scan',
60
+ scheduleType: 'recurring',
61
+ scheduleDescription: 'Every Monday at 08:00',
62
+ nextRunAt: '2026-03-10T08:00:00.000Z',
63
+ overlapPolicy: 'skip',
64
+ taskTitle: 'Security vulnerability scan',
65
+ },
66
+ });
67
+ const result = await callCap('create_schedule', mockClient, {
68
+ name: 'Weekly security scan',
69
+ task_title: 'Security vulnerability scan',
70
+ task_description: 'Run security scan on the entire codebase',
71
+ schedule_type: 'recurring',
72
+ frequency: 'weekly',
73
+ time: '08:00',
74
+ timezone: 'Asia/Jerusalem',
75
+ day_of_week: 1,
76
+ });
77
+ expect(mockClient.createSchedule).toHaveBeenCalledOnce();
78
+ const callArgs = mockClient.createSchedule.mock.calls[0][0];
79
+ expect(callArgs.schedule_config.frequency).toBe('weekly');
80
+ expect(callArgs.schedule_config.dayOfWeek).toBe(1);
81
+ expect(result.content[0].text).toContain('sched_def456');
82
+ });
83
+ it('creates a one-time schedule', async () => {
84
+ mockClient.createSchedule.mockResolvedValueOnce({
85
+ schedule: {
86
+ id: 'sched_onetime1',
87
+ name: 'Release day deploy check',
88
+ scheduleType: 'one_time',
89
+ scheduleDescription: null,
90
+ nextRunAt: '2026-03-15T14:00:00.000Z',
91
+ overlapPolicy: 'allow',
92
+ taskTitle: 'Pre-deployment checklist',
93
+ },
94
+ });
95
+ const result = await callCap('create_schedule', mockClient, {
96
+ name: 'Release day deploy check',
97
+ task_title: 'Pre-deployment checklist',
98
+ task_description: 'Verify all systems before v2.0 deployment',
99
+ schedule_type: 'one_time',
100
+ schedule_at: '2026-03-15T14:00:00.000Z',
101
+ overlap_policy: 'allow',
102
+ });
103
+ expect(mockClient.createSchedule).toHaveBeenCalledOnce();
104
+ const callArgs = mockClient.createSchedule.mock.calls[0][0];
105
+ expect(callArgs.schedule_type).toBe('one_time');
106
+ expect(callArgs.schedule_at).toBe('2026-03-15T14:00:00.000Z');
107
+ expect(callArgs.overlap_policy).toBe('allow');
108
+ expect(result.content[0].text).toContain('sched_onetime1');
109
+ });
110
+ it('uses default values when optional params omitted', async () => {
111
+ mockClient.createSchedule.mockResolvedValueOnce({
112
+ schedule: {
113
+ id: 'sched_default1',
114
+ name: 'Test schedule',
115
+ scheduleType: 'recurring',
116
+ scheduleDescription: 'Daily at 09:00',
117
+ nextRunAt: '2026-03-06T09:00:00.000Z',
118
+ overlapPolicy: 'skip',
119
+ taskTitle: 'Test task',
120
+ },
121
+ });
122
+ const result = await callCap('create_schedule', mockClient, {
123
+ name: 'Test schedule',
124
+ task_title: 'Test task',
125
+ task_description: 'A test description',
126
+ schedule_type: 'recurring',
127
+ });
128
+ const callArgs = mockClient.createSchedule.mock.calls[0][0];
129
+ expect(callArgs.task_priority).toBe('medium');
130
+ expect(callArgs.overlap_policy).toBe('skip');
131
+ expect(callArgs.schedule_config.frequency).toBe('daily');
132
+ expect(callArgs.schedule_config.time).toBe('09:00');
133
+ expect(callArgs.schedule_config.timezone).toBe('Asia/Jerusalem');
134
+ });
135
+ });
136
+ // ============================================
137
+ // List Schedules
138
+ // ============================================
139
+ describe('Schedule: List Schedules', () => {
140
+ beforeEach(() => {
141
+ vi.resetAllMocks();
142
+ });
143
+ it('lists schedules with status and run info', async () => {
144
+ mockClient.listSchedules.mockResolvedValueOnce({
145
+ schedules: [
146
+ {
147
+ id: 'sched_abc123',
148
+ name: 'Daily code review',
149
+ enabled: true,
150
+ paused: false,
151
+ scheduleDescription: 'Daily at 09:00',
152
+ nextRunAt: '2026-03-06T09:00:00.000Z',
153
+ lastRunAt: '2026-03-05T09:00:00.000Z',
154
+ lastRunStatus: 'success',
155
+ totalRuns: 42,
156
+ totalSuccesses: 41,
157
+ totalFailures: 1,
158
+ },
159
+ {
160
+ id: 'sched_def456',
161
+ name: 'Weekly security scan',
162
+ enabled: true,
163
+ paused: true,
164
+ scheduleDescription: 'Every Monday at 08:00',
165
+ nextRunAt: null,
166
+ lastRunAt: '2026-03-03T08:00:00.000Z',
167
+ lastRunStatus: 'failed',
168
+ totalRuns: 10,
169
+ totalSuccesses: 8,
170
+ totalFailures: 2,
171
+ },
172
+ ],
173
+ });
174
+ const result = await callCap('list_schedules', mockClient, {});
175
+ expect(mockClient.listSchedules).toHaveBeenCalledOnce();
176
+ expect(result.content[0].text).toContain('Agent Schedules (2)');
177
+ expect(result.content[0].text).toContain('Daily code review');
178
+ expect(result.content[0].text).toContain('Weekly security scan');
179
+ expect(result.content[0].text).toContain('Active');
180
+ expect(result.content[0].text).toContain('Paused');
181
+ });
182
+ it('shows empty state when no schedules', async () => {
183
+ mockClient.listSchedules.mockResolvedValueOnce({
184
+ schedules: [],
185
+ });
186
+ const result = await callCap('list_schedules', mockClient, {});
187
+ expect(result.content[0].text).toContain('No agent schedules found');
188
+ });
189
+ it('passes filter options to client', async () => {
190
+ mockClient.listSchedules.mockResolvedValueOnce({ schedules: [] });
191
+ await callCap('list_schedules', mockClient, {
192
+ enabled_only: true,
193
+ limit: 5,
194
+ });
195
+ expect(mockClient.listSchedules).toHaveBeenCalledWith({
196
+ enabled_only: true,
197
+ limit: 5,
198
+ });
199
+ });
200
+ });
201
+ // ============================================
202
+ // Pause Schedule
203
+ // ============================================
204
+ describe('Schedule: Pause/Resume', () => {
205
+ beforeEach(() => {
206
+ vi.resetAllMocks();
207
+ });
208
+ it('pauses a schedule with reason', async () => {
209
+ mockClient.pauseSchedule.mockResolvedValueOnce({ success: true });
210
+ const result = await callCap('pause_schedule', mockClient, {
211
+ schedule_id: 'sched_abc123',
212
+ action: 'pause',
213
+ reason: 'Holiday freeze',
214
+ });
215
+ expect(mockClient.pauseSchedule).toHaveBeenCalledWith({
216
+ schedule_id: 'sched_abc123',
217
+ action: 'pause',
218
+ reason: 'Holiday freeze',
219
+ });
220
+ expect(result.content[0].text).toContain('paused');
221
+ expect(result.content[0].text).toContain('Holiday freeze');
222
+ });
223
+ it('resumes a paused schedule', async () => {
224
+ mockClient.pauseSchedule.mockResolvedValueOnce({ success: true });
225
+ const result = await callCap('pause_schedule', mockClient, {
226
+ schedule_id: 'sched_abc123',
227
+ action: 'resume',
228
+ });
229
+ expect(mockClient.pauseSchedule).toHaveBeenCalledWith({
230
+ schedule_id: 'sched_abc123',
231
+ action: 'resume',
232
+ reason: undefined,
233
+ });
234
+ expect(result.content[0].text).toContain('resumed');
235
+ });
236
+ });
237
+ // ============================================
238
+ // Delete Schedule
239
+ // ============================================
240
+ describe('Schedule: Delete', () => {
241
+ beforeEach(() => {
242
+ vi.resetAllMocks();
243
+ });
244
+ it('deletes a schedule by ID', async () => {
245
+ mockClient.deleteSchedule.mockResolvedValueOnce({ success: true });
246
+ const result = await callCap('delete_schedule', mockClient, {
247
+ schedule_id: 'sched_abc123',
248
+ });
249
+ expect(mockClient.deleteSchedule).toHaveBeenCalledWith('sched_abc123');
250
+ expect(result.content[0].text).toContain('deleted');
251
+ expect(result.content[0].text).toContain('sched_abc123');
252
+ });
253
+ });
254
+ // ============================================
255
+ // Tool Definitions
256
+ // ============================================
257
+ describe('Schedule: Tool Definitions', () => {
258
+ it('exports all 4 schedule tools', async () => {
259
+ const { scheduleTools } = await import('../tools/schedules.js');
260
+ expect(scheduleTools.create_schedule).toBeDefined();
261
+ expect(scheduleTools.list_schedules).toBeDefined();
262
+ expect(scheduleTools.pause_schedule).toBeDefined();
263
+ expect(scheduleTools.delete_schedule).toBeDefined();
264
+ });
265
+ it('create_schedule has correct required fields', async () => {
266
+ const { scheduleTools } = await import('../tools/schedules.js');
267
+ const schema = scheduleTools.create_schedule.inputSchema;
268
+ expect(schema.required).toContain('name');
269
+ expect(schema.required).toContain('task_title');
270
+ expect(schema.required).toContain('task_description');
271
+ expect(schema.required).toContain('schedule_type');
272
+ });
273
+ it('pause_schedule requires schedule_id and action', async () => {
274
+ const { scheduleTools } = await import('../tools/schedules.js');
275
+ const schema = scheduleTools.pause_schedule.inputSchema;
276
+ expect(schema.required).toContain('schedule_id');
277
+ expect(schema.required).toContain('action');
278
+ });
279
+ it('delete_schedule requires schedule_id', async () => {
280
+ const { scheduleTools } = await import('../tools/schedules.js');
281
+ const schema = scheduleTools.delete_schedule.inputSchema;
282
+ expect(schema.required).toContain('schedule_id');
283
+ });
284
+ });
285
+ //# sourceMappingURL=schedule-tools.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schedule-tools.test.js","sourceRoot":"","sources":["../../src/__tests__/schedule-tools.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Server HTTP-mode Gateway Key Tests
3
+ *
4
+ * The CallTool handler must split the session families:
5
+ * - gk_* Bearer session → context.gatewayKey = the token (restores the
6
+ * checkGatewayAuth pre-check + gateway metering that commit 157db598b
7
+ * disabled for ALL families).
8
+ * - dobby_at_ / sk_live_ session → context.gatewayKey stays undefined (the
9
+ * pre-check short-circuits to allowed) and the per-request DobbyClient
10
+ * carries a LAZY, session-memoized provider that exchanges the token for a
11
+ * gk_tmp_* via the web app's internal endpoint.
12
+ *
13
+ * Drives the REAL server factory (server.ts) over real Streamable HTTP with a
14
+ * stub introspection issuer — only tools/index.handleToolCall is spied, so we
15
+ * can inspect the exact ToolContext the handler builds.
16
+ */
17
+ export {};
18
+ //# sourceMappingURL=server-gateway-key.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-gateway-key.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/server-gateway-key.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG"}
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Server HTTP-mode Gateway Key Tests
3
+ *
4
+ * The CallTool handler must split the session families:
5
+ * - gk_* Bearer session → context.gatewayKey = the token (restores the
6
+ * checkGatewayAuth pre-check + gateway metering that commit 157db598b
7
+ * disabled for ALL families).
8
+ * - dobby_at_ / sk_live_ session → context.gatewayKey stays undefined (the
9
+ * pre-check short-circuits to allowed) and the per-request DobbyClient
10
+ * carries a LAZY, session-memoized provider that exchanges the token for a
11
+ * gk_tmp_* via the web app's internal endpoint.
12
+ *
13
+ * Drives the REAL server factory (server.ts) over real Streamable HTTP with a
14
+ * stub introspection issuer — only tools/index.handleToolCall is spied, so we
15
+ * can inspect the exact ToolContext the handler builds.
16
+ */
17
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
18
+ const { handleToolCallSpy } = vi.hoisted(() => ({
19
+ handleToolCallSpy: vi.fn(),
20
+ }));
21
+ vi.mock('../tools/index.js', async (importOriginal) => {
22
+ const actual = await importOriginal();
23
+ return {
24
+ ...actual,
25
+ handleToolCall: handleToolCallSpy,
26
+ };
27
+ });
28
+ /**
29
+ * Spin up a stub issuer + the real HTTP server, run initialize → tools/call
30
+ * with the given bearer, and return the ToolContext handleToolCall received.
31
+ */
32
+ async function callToolOverHttp(bearer) {
33
+ const express = (await import('express')).default;
34
+ const { startHttpServer } = await import('../http-server.js');
35
+ const { createServer } = await import('../server.js');
36
+ const issuer = express();
37
+ issuer.use(express.json());
38
+ issuer.post('/oauth/token/introspect', (_req, res) => {
39
+ res.json({
40
+ active: true,
41
+ user_id: 'pu_gw',
42
+ org_id: 'org_gw',
43
+ tenant_id: 'tenant_gw',
44
+ scope: 'mcp:execute mcp:*',
45
+ client_id: 'key_gw',
46
+ exp: Math.floor(Date.now() / 1000) + 3600,
47
+ });
48
+ });
49
+ const issuerServer = issuer.listen(0);
50
+ const issuerPort = issuerServer.address().port;
51
+ const { server, tokenVerifier } = await startHttpServer({
52
+ port: 0,
53
+ issuerUrl: `http://127.0.0.1:${issuerPort}`,
54
+ mcpPublicUrl: 'http://127.0.0.1:0',
55
+ createMcpServer: () => createServer({ mode: 'http' }),
56
+ });
57
+ const mcpPort = server.address().port;
58
+ const mcpUrl = `http://127.0.0.1:${mcpPort}/mcp`;
59
+ const headers = {
60
+ Authorization: `Bearer ${bearer}`,
61
+ 'Content-Type': 'application/json',
62
+ Accept: 'application/json, text/event-stream',
63
+ };
64
+ try {
65
+ const initRes = await fetch(mcpUrl, {
66
+ method: 'POST',
67
+ headers,
68
+ body: JSON.stringify({
69
+ jsonrpc: '2.0',
70
+ id: 1,
71
+ method: 'initialize',
72
+ params: {
73
+ protocolVersion: '2025-03-26',
74
+ capabilities: {},
75
+ clientInfo: { name: 'gw-probe', version: '0' },
76
+ },
77
+ }),
78
+ });
79
+ expect(initRes.status).toBe(200);
80
+ const sessionId = initRes.headers.get('mcp-session-id');
81
+ const callRes = await fetch(mcpUrl, {
82
+ method: 'POST',
83
+ headers: { ...headers, 'Mcp-Session-Id': sessionId },
84
+ body: JSON.stringify({
85
+ jsonrpc: '2.0',
86
+ id: 2,
87
+ method: 'tools/call',
88
+ params: { name: 'create_task', arguments: { title: 'probe' } },
89
+ }),
90
+ });
91
+ expect(callRes.status).toBe(200);
92
+ await callRes.text();
93
+ }
94
+ finally {
95
+ tokenVerifier.clearCache();
96
+ server.close();
97
+ issuerServer.close();
98
+ }
99
+ expect(handleToolCallSpy).toHaveBeenCalledTimes(1);
100
+ return handleToolCallSpy.mock.calls[0][2];
101
+ }
102
+ describe('CallTool handler — gateway key by session family (HTTP mode)', () => {
103
+ beforeEach(() => {
104
+ handleToolCallSpy.mockReset().mockResolvedValue({
105
+ content: [{ type: 'text', text: 'ok' }],
106
+ });
107
+ });
108
+ afterEach(() => {
109
+ vi.unstubAllGlobals();
110
+ vi.unstubAllEnvs();
111
+ });
112
+ it('gk_ Bearer session: context.gatewayKey = the token (pre-check + metering restored)', async () => {
113
+ const context = await callToolOverHttp('gk_user_test_abc');
114
+ expect(context.gatewayKey).toBe('gk_user_test_abc');
115
+ expect(context.client.apiKey).toBe('gk_user_test_abc');
116
+ // gatewayBearer falls back to the apiKey — which IS the gateway key
117
+ expect(await context.client.gatewayBearer()).toBe('gk_user_test_abc');
118
+ });
119
+ it('dobby_at_ (OAuth) session: context.gatewayKey stays undefined', async () => {
120
+ const context = await callToolOverHttp('dobby_at_test_token');
121
+ expect(context.gatewayKey).toBeUndefined();
122
+ expect(context.client.apiKey).toBe('dobby_at_test_token');
123
+ });
124
+ it('dobby_at_ session client lazily resolves a gk_tmp_ via the internal endpoint — memoized', async () => {
125
+ const context = await callToolOverHttp('dobby_at_test_token2');
126
+ // The provider was NOT invoked during the tool call (lazy)
127
+ // — now stub the exchange and resolve it explicitly.
128
+ vi.stubEnv('INTERNAL_SERVICE_SECRET', 'it-secret');
129
+ const fetchMock = vi.fn().mockResolvedValue({
130
+ ok: true,
131
+ json: () => Promise.resolve({
132
+ success: true,
133
+ data: { gateway_key: 'gk_tmp_from_web' },
134
+ }),
135
+ });
136
+ vi.stubGlobal('fetch', fetchMock);
137
+ expect(await context.client.gatewayBearer()).toBe('gk_tmp_from_web');
138
+ expect(fetchMock).toHaveBeenCalledTimes(1);
139
+ const [url, init] = fetchMock.mock.calls[0];
140
+ expect(String(url)).toContain('/api/v1/internal/mcp/gateway-key');
141
+ expect(init.headers['x-internal-secret']).toBe('it-secret');
142
+ expect(init.headers.Authorization).toBe('Bearer dobby_at_test_token2');
143
+ // Session-memoized: a second resolution reuses the same promise
144
+ expect(await context.client.gatewayBearer()).toBe('gk_tmp_from_web');
145
+ expect(fetchMock).toHaveBeenCalledTimes(1);
146
+ });
147
+ });
148
+ //# sourceMappingURL=server-gateway-key.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-gateway-key.test.js","sourceRoot":"","sources":["../../src/__tests__/server-gateway-key.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Server HTTP-mode User-Scoped PAT Routing Tests (ADR-020 W1b/W1c/W2)
3
+ *
4
+ * A user-scoped PAT (`dobby_pat_*`) carries NO tenant/org pin — the introspect
5
+ * endpoint returns `user_scoped: true` with `tenant_id: null` / `org_id: null`
6
+ * and the AGGREGATE (max) role. The CallTool handler must therefore resolve the
7
+ * per-call target from the tool ARGUMENTS, not from the token:
8
+ *
9
+ * - ORG_CLIENT_TOOLS (memory_store_*, rubric_*, orchestration_config_list) →
10
+ * require an `org_id` arg, which becomes client.organizationId + ctx.orgId;
11
+ * tenantId stays undefined. Missing → helpful error, handleToolCall NOT run.
12
+ * - ORG_ARG_TOOLS (export_policies, validate_policies, apply_guardrail,
13
+ * import_policies) → carry their own `organization_id`; the branch must NOT
14
+ * demand a tenant_id.
15
+ * - everything else is tenant-scoped → require a `tenant_id` arg → ctx.tenantId,
16
+ * plus a per-TENANT-memoized gk_tmp_ provider on the client. Missing → error.
17
+ * - ListTools for a user-scoped session appends the two synthetic discovery
18
+ * tools (list_my_tenants + list_my_orgs); a tenant-pinned session gets neither.
19
+ *
20
+ * Drives the REAL server factory (server.ts) over real Streamable HTTP with a
21
+ * stub introspection issuer — only tools/index.handleToolCall is spied, so we
22
+ * inspect the exact ToolContext the handler built, and we also return the parsed
23
+ * tools/call JSON-RPC result so the "missing arg" branches can assert isError.
24
+ *
25
+ * Fixture note — `tenant_role: 'tenant_owner'` (NOT the plain `'owner'` shown in
26
+ * the ADR-020 ticket example): introspection emits roles in the capability-core
27
+ * vocabulary (web `aggregate-roles.ts` maps DB `owner` → `tenant_owner`), and the
28
+ * MCP role-cap (capability-core `roleCapAllows`) only recognizes `tenant_owner`
29
+ * — `'owner'` is an unknown role and fails the cap (verified), which would make
30
+ * every call hit a role denial before handleToolCall. `tenant_owner` is the real
31
+ * in-band value and satisfies the spec's intent (calls reach handleToolCall).
32
+ */
33
+ export {};
34
+ //# sourceMappingURL=server-user-scoped.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-user-scoped.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/server-user-scoped.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG"}