@vibescope/mcp-server 0.1.0 → 0.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 (39) hide show
  1. package/README.md +1 -1
  2. package/dist/api-client.d.ts +56 -1
  3. package/dist/api-client.js +17 -2
  4. package/dist/handlers/bodies-of-work.js +3 -2
  5. package/dist/handlers/deployment.js +3 -2
  6. package/dist/handlers/discovery.d.ts +3 -0
  7. package/dist/handlers/discovery.js +20 -652
  8. package/dist/handlers/fallback.js +18 -9
  9. package/dist/handlers/findings.d.ts +8 -1
  10. package/dist/handlers/findings.js +24 -3
  11. package/dist/handlers/session.js +23 -8
  12. package/dist/handlers/sprints.js +3 -2
  13. package/dist/handlers/tasks.js +22 -1
  14. package/dist/handlers/tool-docs.d.ts +4 -3
  15. package/dist/handlers/tool-docs.js +252 -5
  16. package/dist/handlers/validation.js +13 -1
  17. package/dist/index.js +25 -7
  18. package/dist/tools.js +30 -4
  19. package/package.json +1 -1
  20. package/src/api-client.ts +72 -2
  21. package/src/handlers/__test-setup__.ts +5 -0
  22. package/src/handlers/bodies-of-work.ts +27 -11
  23. package/src/handlers/deployment.ts +4 -2
  24. package/src/handlers/discovery.ts +23 -740
  25. package/src/handlers/fallback.test.ts +78 -0
  26. package/src/handlers/fallback.ts +20 -9
  27. package/src/handlers/findings.test.ts +129 -2
  28. package/src/handlers/findings.ts +32 -3
  29. package/src/handlers/session.test.ts +37 -2
  30. package/src/handlers/session.ts +29 -8
  31. package/src/handlers/sprints.ts +19 -6
  32. package/src/handlers/tasks.test.ts +61 -0
  33. package/src/handlers/tasks.ts +26 -1
  34. package/src/handlers/tool-docs.ts +1024 -0
  35. package/src/handlers/validation.test.ts +52 -0
  36. package/src/handlers/validation.ts +14 -1
  37. package/src/index.ts +25 -7
  38. package/src/tools.ts +30 -4
  39. package/src/knowledge.ts +0 -230
package/dist/tools.js CHANGED
@@ -881,15 +881,29 @@ Returns session info, persona, role, and next task. Use mode:'full' for complete
881
881
  },
882
882
  {
883
883
  name: 'get_findings',
884
- description: `Get findings for a project, optionally filtered by category, severity, or status.`,
884
+ description: `Get findings for a project, optionally filtered by category, severity, or status. Use summary_only=true to reduce token usage by returning only essential fields (id, title, category, severity, status). For just counts, use get_findings_stats instead.`,
885
885
  inputSchema: {
886
886
  type: 'object',
887
887
  properties: {
888
888
  project_id: { type: 'string', description: 'Project UUID' },
889
889
  category: { type: 'string', enum: ['performance', 'security', 'code_quality', 'accessibility', 'documentation', 'architecture', 'testing', 'other'], description: 'Filter by category (optional)' },
890
890
  severity: { type: 'string', enum: ['info', 'low', 'medium', 'high', 'critical'], description: 'Filter by severity (optional)' },
891
- status: { type: 'string', enum: ['open', 'addressed', 'dismissed', 'wontfix'], description: 'Filter by status (default: all)' },
892
- limit: { type: 'number', description: 'Max number of findings to return (default 50)' },
891
+ status: { type: 'string', enum: ['open', 'addressed', 'dismissed', 'wontfix'], description: 'Filter by status (default: open)' },
892
+ limit: { type: 'number', description: 'Max number of findings to return (default 50, max 200)' },
893
+ offset: { type: 'number', description: 'Number of findings to skip for pagination (default 0)' },
894
+ search_query: { type: 'string', description: 'Search findings by title' },
895
+ summary_only: { type: 'boolean', description: 'When true, returns only id, title, category, severity, status (reduces tokens by ~80%). Default: false' },
896
+ },
897
+ required: ['project_id'],
898
+ },
899
+ },
900
+ {
901
+ name: 'get_findings_stats',
902
+ description: `Get aggregate statistics about findings for a project. Returns total count and breakdowns by status, severity, and category. Much more token-efficient than get_findings when you just need to understand the overall state.`,
903
+ inputSchema: {
904
+ type: 'object',
905
+ properties: {
906
+ project_id: { type: 'string', description: 'Project UUID' },
893
907
  },
894
908
  required: ['project_id'],
895
909
  },
@@ -1100,6 +1114,10 @@ Returns subtasks with aggregate completion stats.`,
1100
1114
  type: 'string',
1101
1115
  description: 'Session ID from start_work_session (optional, uses current session if not provided)',
1102
1116
  },
1117
+ current_worktree_path: {
1118
+ type: ['string', 'null'],
1119
+ description: 'Report your current git worktree path (e.g., "../project-task-abc123"). Set to null to clear.',
1120
+ },
1103
1121
  },
1104
1122
  },
1105
1123
  },
@@ -1149,7 +1167,7 @@ Returns subtasks with aggregate completion stats.`,
1149
1167
  },
1150
1168
  {
1151
1169
  name: 'validate_task',
1152
- description: 'Validate a completed task. Include test results in validation_notes.',
1170
+ description: 'Validate a completed task. Include test results in validation_notes. For github-flow/git-flow projects, a PR must exist before approval (add via add_task_reference).',
1153
1171
  inputSchema: {
1154
1172
  type: 'object',
1155
1173
  properties: {
@@ -1165,6 +1183,10 @@ Returns subtasks with aggregate completion stats.`,
1165
1183
  type: 'boolean',
1166
1184
  description: 'Whether the task passes validation (true = approved, false = needs more work)',
1167
1185
  },
1186
+ skip_pr_check: {
1187
+ type: 'boolean',
1188
+ description: 'Skip PR existence check (use only for tasks that legitimately do not need a PR)',
1189
+ },
1168
1190
  },
1169
1191
  required: ['task_id', 'approved'],
1170
1192
  },
@@ -1348,6 +1370,10 @@ Returns subtasks with aggregate completion stats.`,
1348
1370
  type: 'boolean',
1349
1371
  description: 'When true, converted task blocks all other work until complete',
1350
1372
  },
1373
+ recurring: {
1374
+ type: 'boolean',
1375
+ description: 'When true, requirement resets to pending when a new deployment is requested',
1376
+ },
1351
1377
  },
1352
1378
  required: ['project_id', 'type', 'title'],
1353
1379
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibescope/mcp-server",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "MCP server for Vibescope - AI project tracking tools",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/src/api-client.ts CHANGED
@@ -137,13 +137,16 @@ export class VibescopeApiClient {
137
137
  return this.request('POST', '/api/mcp/sessions/start', params);
138
138
  }
139
139
 
140
- async heartbeat(sessionId: string): Promise<ApiResponse<{
140
+ async heartbeat(sessionId: string, options?: {
141
+ current_worktree_path?: string | null;
142
+ }): Promise<ApiResponse<{
141
143
  success: boolean;
142
144
  session_id: string;
143
145
  timestamp: string;
144
146
  }>> {
145
147
  return this.request('POST', '/api/mcp/sessions/heartbeat', {
146
- session_id: sessionId
148
+ session_id: sessionId,
149
+ ...options
147
150
  });
148
151
  }
149
152
 
@@ -381,6 +384,20 @@ export class VibescopeApiClient {
381
384
  }): Promise<ApiResponse<{
382
385
  success: boolean;
383
386
  task_id: string;
387
+ git_workflow?: {
388
+ workflow: string;
389
+ base_branch: string;
390
+ suggested_branch: string;
391
+ worktree_required: boolean;
392
+ };
393
+ worktree_setup?: {
394
+ message: string;
395
+ commands: string[];
396
+ worktree_path: string;
397
+ branch_name: string;
398
+ cleanup_command: string;
399
+ };
400
+ next_step?: string;
384
401
  }>> {
385
402
  return this.request('PATCH', `/api/mcp/tasks/${taskId}`, updates);
386
403
  }
@@ -405,6 +422,7 @@ export class VibescopeApiClient {
405
422
  deployment?: string;
406
423
  };
407
424
  next_action: string;
425
+ warnings?: string[];
408
426
  }>> {
409
427
  return this.request('POST', `/api/mcp/tasks/${taskId}/complete`, params);
410
428
  }
@@ -642,6 +660,9 @@ export class VibescopeApiClient {
642
660
  severity?: string;
643
661
  status?: string;
644
662
  limit?: number;
663
+ offset?: number;
664
+ search_query?: string;
665
+ summary_only?: boolean;
645
666
  }): Promise<ApiResponse<{
646
667
  findings: Array<{
647
668
  id: string;
@@ -655,6 +676,8 @@ export class VibescopeApiClient {
655
676
  resolution_note?: string;
656
677
  created_at: string;
657
678
  }>;
679
+ total_count?: number;
680
+ has_more?: boolean;
658
681
  }>> {
659
682
  return this.proxy('get_findings', {
660
683
  project_id: projectId,
@@ -662,6 +685,17 @@ export class VibescopeApiClient {
662
685
  });
663
686
  }
664
687
 
688
+ async getFindingsStats(projectId: string): Promise<ApiResponse<{
689
+ total: number;
690
+ by_status: Record<string, number>;
691
+ by_severity: Record<string, number>;
692
+ by_category: Record<string, number>;
693
+ }>> {
694
+ return this.proxy('get_findings_stats', {
695
+ project_id: projectId
696
+ });
697
+ }
698
+
665
699
  async addFinding(projectId: string, params: {
666
700
  title: string;
667
701
  description?: string;
@@ -839,11 +873,13 @@ export class VibescopeApiClient {
839
873
  async validateTask(taskId: string, params: {
840
874
  approved: boolean;
841
875
  validation_notes?: string;
876
+ skip_pr_check?: boolean;
842
877
  }, sessionId?: string): Promise<ApiResponse<{
843
878
  success: boolean;
844
879
  approved: boolean;
845
880
  task_id: string;
846
881
  message?: string;
882
+ workflow?: string;
847
883
  }>> {
848
884
  return this.proxy('validate_task', {
849
885
  task_id: taskId,
@@ -858,6 +894,21 @@ export class VibescopeApiClient {
858
894
  success: boolean;
859
895
  activity: string;
860
896
  message: string;
897
+ git_workflow?: {
898
+ workflow: string;
899
+ base_branch: string;
900
+ worktree_recommended: boolean;
901
+ note: string;
902
+ };
903
+ worktree_setup?: {
904
+ message: string;
905
+ commands: string[];
906
+ worktree_path: string;
907
+ branch_name: string;
908
+ cleanup_command: string;
909
+ report_worktree: string;
910
+ };
911
+ next_step?: string;
861
912
  }>> {
862
913
  return this.proxy('start_fallback_activity', {
863
914
  project_id: projectId,
@@ -1591,6 +1642,7 @@ export class VibescopeApiClient {
1591
1642
  file_path?: string;
1592
1643
  stage?: string;
1593
1644
  blocking?: boolean;
1645
+ recurring?: boolean;
1594
1646
  }): Promise<ApiResponse<{
1595
1647
  success: boolean;
1596
1648
  requirement_id: string;
@@ -1730,6 +1782,24 @@ export class VibescopeApiClient {
1730
1782
  readme_content: readmeContent
1731
1783
  });
1732
1784
  }
1785
+
1786
+ // ============================================================================
1787
+ // Help Topics (database-backed)
1788
+ // ============================================================================
1789
+ async getHelpTopic(slug: string): Promise<ApiResponse<{
1790
+ slug: string;
1791
+ title: string;
1792
+ content: string;
1793
+ } | null>> {
1794
+ return this.proxy('get_help_topic', { slug });
1795
+ }
1796
+
1797
+ async getHelpTopics(): Promise<ApiResponse<Array<{
1798
+ slug: string;
1799
+ title: string;
1800
+ }>>> {
1801
+ return this.proxy('get_help_topics', {});
1802
+ }
1733
1803
  }
1734
1804
 
1735
1805
  // Singleton instance
@@ -77,6 +77,7 @@ export const mockApiClient = {
77
77
  // Findings
78
78
  addFinding: vi.fn(),
79
79
  getFindings: vi.fn(),
80
+ getFindingsStats: vi.fn(),
80
81
  updateFinding: vi.fn(),
81
82
  deleteFinding: vi.fn(),
82
83
 
@@ -164,6 +165,10 @@ export const mockApiClient = {
164
165
  claimValidation: vi.fn(),
165
166
  validateTask: vi.fn(),
166
167
 
168
+ // Help Topics
169
+ getHelpTopic: vi.fn(),
170
+ getHelpTopics: vi.fn(),
171
+
167
172
  // Proxy (generic)
168
173
  proxy: vi.fn(),
169
174
  };
@@ -134,24 +134,40 @@ export const updateBodyOfWork: Handler = async (args, ctx) => {
134
134
  };
135
135
 
136
136
  export const getBodyOfWork: Handler = async (args, ctx) => {
137
- const { body_of_work_id } = args as { body_of_work_id: string };
137
+ const { body_of_work_id, summary_only = false } = args as { body_of_work_id: string; summary_only?: boolean };
138
138
 
139
139
  validateRequired(body_of_work_id, 'body_of_work_id');
140
140
  validateUUID(body_of_work_id, 'body_of_work_id');
141
141
 
142
142
  const apiClient = getApiClient();
143
143
 
144
+ // Response type varies based on summary_only
144
145
  const response = await apiClient.proxy<{
145
- id: string;
146
- title: string;
147
- description?: string;
148
- status: string;
149
- progress_percentage: number;
150
- pre_tasks: unknown[];
151
- core_tasks: unknown[];
152
- post_tasks: unknown[];
153
- total_tasks: number;
154
- }>('get_body_of_work', { body_of_work_id });
146
+ body_of_work: {
147
+ id: string;
148
+ title: string;
149
+ description?: string;
150
+ status: string;
151
+ progress_percentage: number;
152
+ };
153
+ // Full response includes tasks grouped by phase
154
+ tasks?: {
155
+ pre: unknown[];
156
+ core: unknown[];
157
+ post: unknown[];
158
+ };
159
+ // Summary response includes counts and next task
160
+ task_counts?: {
161
+ pre: { total: number; completed: number };
162
+ core: { total: number; completed: number };
163
+ post: { total: number; completed: number };
164
+ total: number;
165
+ completed: number;
166
+ in_progress: number;
167
+ };
168
+ current_task?: { id: string; title: string } | null;
169
+ next_task?: { id: string; title: string; priority: number } | null;
170
+ }>('get_body_of_work', { body_of_work_id, summary_only });
155
171
 
156
172
  if (!response.ok) {
157
173
  throw new Error(`Failed to get body of work: ${response.error}`);
@@ -198,7 +198,7 @@ export const cancelDeployment: Handler = async (args, ctx) => {
198
198
  };
199
199
 
200
200
  export const addDeploymentRequirement: Handler = async (args, ctx) => {
201
- const { project_id, type, title, description, file_path, stage = 'preparation', blocking = false } = args as {
201
+ const { project_id, type, title, description, file_path, stage = 'preparation', blocking = false, recurring = false } = args as {
202
202
  project_id: string;
203
203
  type: string;
204
204
  title: string;
@@ -206,6 +206,7 @@ export const addDeploymentRequirement: Handler = async (args, ctx) => {
206
206
  file_path?: string;
207
207
  stage?: string;
208
208
  blocking?: boolean;
209
+ recurring?: boolean;
209
210
  };
210
211
 
211
212
  validateRequired(project_id, 'project_id');
@@ -230,7 +231,8 @@ export const addDeploymentRequirement: Handler = async (args, ctx) => {
230
231
  description,
231
232
  file_path,
232
233
  stage: stage as 'preparation' | 'deployment' | 'verification',
233
- blocking
234
+ blocking,
235
+ recurring
234
236
  });
235
237
 
236
238
  if (!response.ok) {