@vibescope/mcp-server 0.2.1 → 0.2.2

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 (93) hide show
  1. package/README.md +60 -7
  2. package/dist/api-client.d.ts +187 -0
  3. package/dist/api-client.js +48 -0
  4. package/dist/handlers/blockers.js +9 -8
  5. package/dist/handlers/bodies-of-work.js +14 -14
  6. package/dist/handlers/connectors.d.ts +45 -0
  7. package/dist/handlers/connectors.js +183 -0
  8. package/dist/handlers/cost.d.ts +10 -0
  9. package/dist/handlers/cost.js +54 -0
  10. package/dist/handlers/decisions.js +3 -3
  11. package/dist/handlers/deployment.js +35 -19
  12. package/dist/handlers/discovery.d.ts +7 -0
  13. package/dist/handlers/discovery.js +61 -2
  14. package/dist/handlers/fallback.js +5 -4
  15. package/dist/handlers/file-checkouts.d.ts +2 -0
  16. package/dist/handlers/file-checkouts.js +38 -6
  17. package/dist/handlers/findings.js +13 -12
  18. package/dist/handlers/git-issues.js +4 -4
  19. package/dist/handlers/ideas.js +5 -5
  20. package/dist/handlers/index.d.ts +1 -0
  21. package/dist/handlers/index.js +3 -0
  22. package/dist/handlers/milestones.js +5 -5
  23. package/dist/handlers/organizations.js +13 -13
  24. package/dist/handlers/progress.js +2 -2
  25. package/dist/handlers/project.js +6 -6
  26. package/dist/handlers/requests.js +3 -3
  27. package/dist/handlers/session.js +28 -9
  28. package/dist/handlers/sprints.js +17 -17
  29. package/dist/handlers/tasks.d.ts +2 -0
  30. package/dist/handlers/tasks.js +78 -20
  31. package/dist/handlers/types.d.ts +64 -2
  32. package/dist/handlers/types.js +48 -1
  33. package/dist/handlers/validation.js +3 -3
  34. package/dist/index.js +7 -2716
  35. package/dist/token-tracking.d.ts +74 -0
  36. package/dist/token-tracking.js +122 -0
  37. package/dist/tools.js +298 -9
  38. package/dist/utils.d.ts +5 -0
  39. package/dist/utils.js +17 -0
  40. package/docs/TOOLS.md +2053 -0
  41. package/package.json +4 -1
  42. package/scripts/generate-docs.ts +212 -0
  43. package/src/api-client.test.ts +718 -0
  44. package/src/api-client.ts +231 -0
  45. package/src/handlers/__test-setup__.ts +9 -0
  46. package/src/handlers/blockers.test.ts +31 -19
  47. package/src/handlers/blockers.ts +9 -8
  48. package/src/handlers/bodies-of-work.test.ts +55 -32
  49. package/src/handlers/bodies-of-work.ts +14 -14
  50. package/src/handlers/connectors.test.ts +834 -0
  51. package/src/handlers/connectors.ts +229 -0
  52. package/src/handlers/cost.ts +66 -0
  53. package/src/handlers/decisions.test.ts +34 -25
  54. package/src/handlers/decisions.ts +3 -3
  55. package/src/handlers/deployment.ts +39 -19
  56. package/src/handlers/discovery.ts +61 -2
  57. package/src/handlers/fallback.test.ts +26 -22
  58. package/src/handlers/fallback.ts +5 -4
  59. package/src/handlers/file-checkouts.test.ts +242 -49
  60. package/src/handlers/file-checkouts.ts +44 -6
  61. package/src/handlers/findings.test.ts +38 -24
  62. package/src/handlers/findings.ts +13 -12
  63. package/src/handlers/git-issues.test.ts +51 -43
  64. package/src/handlers/git-issues.ts +4 -4
  65. package/src/handlers/ideas.test.ts +28 -23
  66. package/src/handlers/ideas.ts +5 -5
  67. package/src/handlers/index.ts +3 -0
  68. package/src/handlers/milestones.test.ts +33 -28
  69. package/src/handlers/milestones.ts +5 -5
  70. package/src/handlers/organizations.test.ts +104 -83
  71. package/src/handlers/organizations.ts +13 -13
  72. package/src/handlers/progress.test.ts +20 -14
  73. package/src/handlers/progress.ts +2 -2
  74. package/src/handlers/project.test.ts +34 -27
  75. package/src/handlers/project.ts +6 -6
  76. package/src/handlers/requests.test.ts +27 -18
  77. package/src/handlers/requests.ts +3 -3
  78. package/src/handlers/session.test.ts +47 -0
  79. package/src/handlers/session.ts +32 -9
  80. package/src/handlers/sprints.test.ts +71 -50
  81. package/src/handlers/sprints.ts +17 -17
  82. package/src/handlers/tasks.test.ts +77 -15
  83. package/src/handlers/tasks.ts +90 -21
  84. package/src/handlers/tool-categories.test.ts +66 -0
  85. package/src/handlers/types.ts +81 -2
  86. package/src/handlers/validation.test.ts +78 -45
  87. package/src/handlers/validation.ts +3 -3
  88. package/src/index.ts +12 -2732
  89. package/src/token-tracking.test.ts +453 -0
  90. package/src/token-tracking.ts +164 -0
  91. package/src/tools.ts +298 -9
  92. package/src/utils.test.ts +2 -2
  93. package/src/utils.ts +17 -0
@@ -138,19 +138,20 @@ describe('addIdea', () => {
138
138
  );
139
139
  });
140
140
 
141
- it('should throw error when API call fails', async () => {
141
+ it('should return error when API call fails', async () => {
142
142
  mockApiClient.addIdea.mockResolvedValue({
143
143
  ok: false,
144
144
  error: 'Insert failed',
145
145
  });
146
146
  const ctx = createMockContext();
147
147
 
148
- await expect(
149
- addIdea({
150
- project_id: '123e4567-e89b-12d3-a456-426614174000',
151
- title: 'New Feature',
152
- }, ctx)
153
- ).rejects.toThrow('Failed to add idea');
148
+ const result = await addIdea({
149
+ project_id: '123e4567-e89b-12d3-a456-426614174000',
150
+ title: 'New Feature',
151
+ }, ctx);
152
+
153
+ expect(result.isError).toBe(true);
154
+ expect(result.result).toMatchObject({ error: 'Insert failed' });
154
155
  });
155
156
  });
156
157
 
@@ -248,16 +249,17 @@ describe('updateIdea', () => {
248
249
  );
249
250
  });
250
251
 
251
- it('should throw error when API call fails', async () => {
252
+ it('should return error when API call fails', async () => {
252
253
  mockApiClient.updateIdea.mockResolvedValue({
253
254
  ok: false,
254
255
  error: 'Idea not found',
255
256
  });
256
257
  const ctx = createMockContext();
257
258
 
258
- await expect(
259
- updateIdea({ idea_id: '123e4567-e89b-12d3-a456-426614174000', title: 'New' }, ctx)
260
- ).rejects.toThrow('Failed to update idea');
259
+ const result = await updateIdea({ idea_id: '123e4567-e89b-12d3-a456-426614174000', title: 'New' }, ctx);
260
+
261
+ expect(result.isError).toBe(true);
262
+ expect(result.result).toMatchObject({ error: 'Idea not found' });
261
263
  });
262
264
  });
263
265
 
@@ -363,16 +365,17 @@ describe('getIdeas', () => {
363
365
  );
364
366
  });
365
367
 
366
- it('should throw error when API call fails', async () => {
368
+ it('should return error when API call fails', async () => {
367
369
  mockApiClient.getIdeas.mockResolvedValue({
368
370
  ok: false,
369
371
  error: 'Query failed',
370
372
  });
371
373
  const ctx = createMockContext();
372
374
 
373
- await expect(
374
- getIdeas({ project_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx)
375
- ).rejects.toThrow('Failed to fetch ideas');
375
+ const result = await getIdeas({ project_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx);
376
+
377
+ expect(result.isError).toBe(true);
378
+ expect(result.result).toMatchObject({ error: 'Query failed' });
376
379
  });
377
380
  });
378
381
 
@@ -429,16 +432,17 @@ describe('deleteIdea', () => {
429
432
  );
430
433
  });
431
434
 
432
- it('should throw error when API call fails', async () => {
435
+ it('should return error when API call fails', async () => {
433
436
  mockApiClient.deleteIdea.mockResolvedValue({
434
437
  ok: false,
435
438
  error: 'Delete failed',
436
439
  });
437
440
  const ctx = createMockContext();
438
441
 
439
- await expect(
440
- deleteIdea({ idea_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx)
441
- ).rejects.toThrow('Failed to delete idea');
442
+ const result = await deleteIdea({ idea_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx);
443
+
444
+ expect(result.isError).toBe(true);
445
+ expect(result.result).toMatchObject({ error: 'Delete failed' });
442
446
  });
443
447
  });
444
448
 
@@ -625,15 +629,16 @@ describe('convertIdeaToTask', () => {
625
629
  );
626
630
  });
627
631
 
628
- it('should throw error when API call fails', async () => {
632
+ it('should return error when API call fails', async () => {
629
633
  mockApiClient.proxy.mockResolvedValue({
630
634
  ok: false,
631
635
  error: 'Idea not found',
632
636
  });
633
637
  const ctx = createMockContext();
634
638
 
635
- await expect(
636
- convertIdeaToTask({ idea_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx)
637
- ).rejects.toThrow('Failed to convert idea');
639
+ const result = await convertIdeaToTask({ idea_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx);
640
+
641
+ expect(result.isError).toBe(true);
642
+ expect(result.result).toMatchObject({ error: 'Idea not found' });
638
643
  });
639
644
  });
@@ -72,7 +72,7 @@ export const addIdea: Handler = async (args, ctx) => {
72
72
  }, session.currentSessionId || undefined);
73
73
 
74
74
  if (!response.ok) {
75
- throw new Error(`Failed to add idea: ${response.error}`);
75
+ return { result: { error: response.error || 'Failed to add idea' }, isError: true };
76
76
  }
77
77
 
78
78
  return { result: { success: true, idea_id: response.data?.idea_id, title } };
@@ -91,7 +91,7 @@ export const updateIdea: Handler = async (args, _ctx) => {
91
91
  });
92
92
 
93
93
  if (!response.ok) {
94
- throw new Error(`Failed to update idea: ${response.error}`);
94
+ return { result: { error: response.error || 'Failed to update idea' }, isError: true };
95
95
  }
96
96
 
97
97
  return { result: { success: true, idea_id } };
@@ -110,7 +110,7 @@ export const getIdeas: Handler = async (args, _ctx) => {
110
110
  });
111
111
 
112
112
  if (!response.ok) {
113
- throw new Error(`Failed to fetch ideas: ${response.error}`);
113
+ return { result: { error: response.error || 'Failed to fetch ideas' }, isError: true };
114
114
  }
115
115
 
116
116
  return {
@@ -128,7 +128,7 @@ export const deleteIdea: Handler = async (args, _ctx) => {
128
128
  const response = await apiClient.deleteIdea(idea_id);
129
129
 
130
130
  if (!response.ok) {
131
- throw new Error(`Failed to delete idea: ${response.error}`);
131
+ return { result: { error: response.error || 'Failed to delete idea' }, isError: true };
132
132
  }
133
133
 
134
134
  return { result: { success: true } };
@@ -157,7 +157,7 @@ export const convertIdeaToTask: Handler = async (args, _ctx) => {
157
157
  });
158
158
 
159
159
  if (!response.ok) {
160
- throw new Error(`Failed to convert idea: ${response.error}`);
160
+ return { result: { error: response.error || 'Failed to convert idea' }, isError: true };
161
161
  }
162
162
 
163
163
  return { result: response.data };
@@ -27,6 +27,7 @@ export * from './git-issues.js';
27
27
  export * from './sprints.js';
28
28
  export * from './file-checkouts.js';
29
29
  export * from './roles.js';
30
+ export * from './connectors.js';
30
31
 
31
32
  import type { HandlerRegistry } from './types.js';
32
33
  import { milestoneHandlers } from './milestones.js';
@@ -50,6 +51,7 @@ import { gitIssueHandlers } from './git-issues.js';
50
51
  import { sprintHandlers } from './sprints.js';
51
52
  import { fileCheckoutHandlers } from './file-checkouts.js';
52
53
  import { roleHandlers } from './roles.js';
54
+ import { connectorHandlers } from './connectors.js';
53
55
 
54
56
  /**
55
57
  * Build the complete handler registry from all modules
@@ -77,5 +79,6 @@ export function buildHandlerRegistry(): HandlerRegistry {
77
79
  ...sprintHandlers,
78
80
  ...fileCheckoutHandlers,
79
81
  ...roleHandlers,
82
+ ...connectorHandlers,
80
83
  };
81
84
  }
@@ -90,19 +90,20 @@ describe('addMilestone', () => {
90
90
  );
91
91
  });
92
92
 
93
- it('should throw error when API call fails', async () => {
93
+ it('should return error when API call fails', async () => {
94
94
  mockApiClient.addMilestone.mockResolvedValue({
95
95
  ok: false,
96
96
  error: 'Task not found',
97
97
  });
98
98
  const ctx = createMockContext();
99
99
 
100
- await expect(
101
- addMilestone({
102
- task_id: '123e4567-e89b-12d3-a456-426614174000',
103
- title: 'Milestone 1',
104
- }, ctx)
105
- ).rejects.toThrow('Failed to add milestone: Task not found');
100
+ const result = await addMilestone({
101
+ task_id: '123e4567-e89b-12d3-a456-426614174000',
102
+ title: 'Milestone 1',
103
+ }, ctx);
104
+
105
+ expect(result.isError).toBe(true);
106
+ expect(result.result).toMatchObject({ error: 'Task not found' });
106
107
  });
107
108
  });
108
109
 
@@ -132,7 +133,7 @@ describe('updateMilestone', () => {
132
133
 
133
134
  await expect(
134
135
  updateMilestone({ milestone_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx)
135
- ).rejects.toThrow('At least one field to update is required');
136
+ ).rejects.toThrow(ValidationError);
136
137
  });
137
138
 
138
139
  it('should throw error for invalid status', async () => {
@@ -143,7 +144,7 @@ describe('updateMilestone', () => {
143
144
  milestone_id: '123e4567-e89b-12d3-a456-426614174000',
144
145
  status: 'invalid_status',
145
146
  }, ctx)
146
- ).rejects.toThrow('Invalid status: "invalid_status"');
147
+ ).rejects.toThrow(ValidationError);
147
148
  });
148
149
 
149
150
  it('should update title successfully', async () => {
@@ -192,19 +193,20 @@ describe('updateMilestone', () => {
192
193
  );
193
194
  });
194
195
 
195
- it('should throw error when API call fails', async () => {
196
+ it('should return error when API call fails', async () => {
196
197
  mockApiClient.updateMilestone.mockResolvedValue({
197
198
  ok: false,
198
199
  error: 'Milestone not found',
199
200
  });
200
201
  const ctx = createMockContext();
201
202
 
202
- await expect(
203
- updateMilestone({
204
- milestone_id: '123e4567-e89b-12d3-a456-426614174000',
205
- title: 'New Title',
206
- }, ctx)
207
- ).rejects.toThrow('Failed to update milestone: Milestone not found');
203
+ const result = await updateMilestone({
204
+ milestone_id: '123e4567-e89b-12d3-a456-426614174000',
205
+ title: 'New Title',
206
+ }, ctx);
207
+
208
+ expect(result.isError).toBe(true);
209
+ expect(result.result).toMatchObject({ error: 'Milestone not found' });
208
210
  });
209
211
  });
210
212
 
@@ -263,16 +265,17 @@ describe('completeMilestone', () => {
263
265
  );
264
266
  });
265
267
 
266
- it('should throw error when API call fails', async () => {
268
+ it('should return error when API call fails', async () => {
267
269
  mockApiClient.completeMilestone.mockResolvedValue({
268
270
  ok: false,
269
271
  error: 'Milestone not found',
270
272
  });
271
273
  const ctx = createMockContext();
272
274
 
273
- await expect(
274
- completeMilestone({ milestone_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx)
275
- ).rejects.toThrow('Failed to complete milestone: Milestone not found');
275
+ const result = await completeMilestone({ milestone_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx);
276
+
277
+ expect(result.isError).toBe(true);
278
+ expect(result.result).toMatchObject({ error: 'Milestone not found' });
276
279
  });
277
280
  });
278
281
 
@@ -332,16 +335,17 @@ describe('deleteMilestone', () => {
332
335
  );
333
336
  });
334
337
 
335
- it('should throw error when API call fails', async () => {
338
+ it('should return error when API call fails', async () => {
336
339
  mockApiClient.deleteMilestone.mockResolvedValue({
337
340
  ok: false,
338
341
  error: 'Milestone not found',
339
342
  });
340
343
  const ctx = createMockContext();
341
344
 
342
- await expect(
343
- deleteMilestone({ milestone_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx)
344
- ).rejects.toThrow('Failed to delete milestone: Milestone not found');
345
+ const result = await deleteMilestone({ milestone_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx);
346
+
347
+ expect(result.isError).toBe(true);
348
+ expect(result.result).toMatchObject({ error: 'Milestone not found' });
345
349
  });
346
350
  });
347
351
 
@@ -456,15 +460,16 @@ describe('getMilestones', () => {
456
460
  );
457
461
  });
458
462
 
459
- it('should throw error when API call fails', async () => {
463
+ it('should return error when API call fails', async () => {
460
464
  mockApiClient.getMilestones.mockResolvedValue({
461
465
  ok: false,
462
466
  error: 'Task not found',
463
467
  });
464
468
  const ctx = createMockContext();
465
469
 
466
- await expect(
467
- getMilestones({ task_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx)
468
- ).rejects.toThrow('Failed to get milestones: Task not found');
470
+ const result = await getMilestones({ task_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx);
471
+
472
+ expect(result.isError).toBe(true);
473
+ expect(result.result).toMatchObject({ error: 'Task not found' });
469
474
  });
470
475
  });
@@ -64,7 +64,7 @@ export const addMilestone: Handler = async (args, ctx) => {
64
64
  }, session.currentSessionId || undefined);
65
65
 
66
66
  if (!response.ok) {
67
- throw new Error(`Failed to add milestone: ${response.error}`);
67
+ return { result: { error: response.error || 'Failed to add milestone' }, isError: true };
68
68
  }
69
69
 
70
70
  return {
@@ -93,7 +93,7 @@ export const updateMilestone: Handler = async (args, _ctx) => {
93
93
  });
94
94
 
95
95
  if (!response.ok) {
96
- throw new Error(`Failed to update milestone: ${response.error}`);
96
+ return { result: { error: response.error || 'Failed to update milestone' }, isError: true };
97
97
  }
98
98
 
99
99
  return {
@@ -112,7 +112,7 @@ export const completeMilestone: Handler = async (args, _ctx) => {
112
112
  const response = await apiClient.completeMilestone(milestone_id);
113
113
 
114
114
  if (!response.ok) {
115
- throw new Error(`Failed to complete milestone: ${response.error}`);
115
+ return { result: { error: response.error || 'Failed to complete milestone' }, isError: true };
116
116
  }
117
117
 
118
118
  return {
@@ -131,7 +131,7 @@ export const deleteMilestone: Handler = async (args, _ctx) => {
131
131
  const response = await apiClient.deleteMilestone(milestone_id);
132
132
 
133
133
  if (!response.ok) {
134
- throw new Error(`Failed to delete milestone: ${response.error}`);
134
+ return { result: { error: response.error || 'Failed to delete milestone' }, isError: true };
135
135
  }
136
136
 
137
137
  return {
@@ -150,7 +150,7 @@ export const getMilestones: Handler = async (args, _ctx) => {
150
150
  const response = await apiClient.getMilestones(task_id);
151
151
 
152
152
  if (!response.ok) {
153
- throw new Error(`Failed to get milestones: ${response.error}`);
153
+ return { result: { error: response.error || 'Failed to get milestones' }, isError: true };
154
154
  }
155
155
 
156
156
  // Stats are calculated server-side now