@vizzly-testing/cli 0.13.1 → 0.13.3

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 (40) hide show
  1. package/README.md +552 -88
  2. package/claude-plugin/.claude-plugin/README.md +4 -0
  3. package/claude-plugin/.mcp.json +4 -0
  4. package/claude-plugin/CHANGELOG.md +27 -0
  5. package/claude-plugin/mcp/vizzly-docs-server/README.md +95 -0
  6. package/claude-plugin/mcp/vizzly-docs-server/docs-fetcher.js +110 -0
  7. package/claude-plugin/mcp/vizzly-docs-server/index.js +283 -0
  8. package/claude-plugin/mcp/vizzly-server/cloud-api-provider.js +26 -10
  9. package/claude-plugin/mcp/vizzly-server/index.js +14 -1
  10. package/claude-plugin/mcp/vizzly-server/local-tdd-provider.js +61 -28
  11. package/dist/cli.js +4 -4
  12. package/dist/commands/run.js +1 -1
  13. package/dist/commands/tdd-daemon.js +54 -8
  14. package/dist/commands/tdd.js +8 -8
  15. package/dist/container/index.js +34 -3
  16. package/dist/reporter/reporter-bundle.css +1 -1
  17. package/dist/reporter/reporter-bundle.iife.js +29 -59
  18. package/dist/server/handlers/tdd-handler.js +18 -16
  19. package/dist/server/http-server.js +473 -4
  20. package/dist/services/config-service.js +371 -0
  21. package/dist/services/project-service.js +245 -0
  22. package/dist/services/server-manager.js +32 -5
  23. package/dist/services/static-report-generator.js +208 -0
  24. package/dist/services/tdd-service.js +14 -6
  25. package/dist/types/reporter/src/components/ui/form-field.d.ts +16 -0
  26. package/dist/types/reporter/src/components/views/projects-view.d.ts +1 -0
  27. package/dist/types/reporter/src/components/views/settings-view.d.ts +1 -0
  28. package/dist/types/reporter/src/hooks/use-auth.d.ts +10 -0
  29. package/dist/types/reporter/src/hooks/use-config.d.ts +9 -0
  30. package/dist/types/reporter/src/hooks/use-projects.d.ts +10 -0
  31. package/dist/types/reporter/src/services/api-client.d.ts +7 -0
  32. package/dist/types/server/http-server.d.ts +1 -1
  33. package/dist/types/services/config-service.d.ts +98 -0
  34. package/dist/types/services/project-service.d.ts +103 -0
  35. package/dist/types/services/server-manager.d.ts +2 -1
  36. package/dist/types/services/static-report-generator.d.ts +25 -0
  37. package/dist/types/services/tdd-service.d.ts +2 -2
  38. package/dist/utils/console-ui.js +26 -2
  39. package/docs/tdd-mode.md +31 -15
  40. package/package.json +4 -4
@@ -130,6 +130,10 @@ The plugin provides an MCP server with direct access to Vizzly data:
130
130
  ### Local TDD Tools
131
131
  - `detect_context` - Detect if using local TDD or cloud mode
132
132
  - `get_tdd_status` - Get current TDD comparison results
133
+ - Parameters:
134
+ - `statusFilter` (optional): Filter by status - `'failed'`, `'new'`, `'passed'`, `'all'`, or `'summary'` (default)
135
+ - `limit` (optional): Maximum number of comparisons to return
136
+ - Default behavior (summary mode): Returns counts only without full comparison details for efficiency
133
137
  - `read_comparison_details` - Detailed info for specific screenshot
134
138
  - `accept_baseline` - Accept a screenshot as new baseline
135
139
  - `reject_baseline` - Reject a baseline with reason
@@ -3,6 +3,10 @@
3
3
  "vizzly": {
4
4
  "command": "node",
5
5
  "args": ["${CLAUDE_PLUGIN_ROOT}/mcp/vizzly-server/index.js"]
6
+ },
7
+ "vizzly-docs": {
8
+ "command": "node",
9
+ "args": ["${CLAUDE_PLUGIN_ROOT}/mcp/vizzly-docs-server/index.js"]
6
10
  }
7
11
  }
8
12
  }
@@ -5,6 +5,33 @@ All notable changes to the Vizzly Claude Code plugin will be documented in this
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ### Added
11
+ - 📚 **New MCP Server:** `vizzly-docs` - Easy access to Vizzly documentation
12
+ - `list_docs` - Browse all docs with optional category filtering
13
+ - `get_doc` - Retrieve full markdown content for any doc page
14
+ - `search_docs` - Keyword search across titles, descriptions, and categories
15
+ - `get_sidebar` - View complete documentation navigation structure
16
+ - Fetches from live docs.vizzly.dev site with intelligent caching
17
+ - ⚡️ **Performance:** `get_tdd_status` now supports filtering and pagination
18
+ - New `statusFilter` parameter: `'failed'`, `'new'`, `'passed'`, `'all'`, or `'summary'` (default)
19
+ - New `limit` parameter for capping number of comparisons returned
20
+ - Default behavior (summary mode) returns only counts for better token efficiency
21
+ - 🔧 **API Enhancement:** Cloud API provider now includes approval status and flaky screenshot detection
22
+ - Added approval status breakdown (pending/approved/rejected/auto_approved)
23
+ - Added flaky screenshot count
24
+ - Added hot spot coverage metadata for quick triage
25
+
26
+ ### Changed
27
+ - 🔧 **Internal:** `acceptBaseline()` in TDD service now accepts both comparison ID (string) or full comparison object
28
+ - Enables accepting baselines from report-data.json without in-memory lookup
29
+ - Fixes issue where accepting from dashboard wasn't working properly
30
+
31
+ ### Fixed
32
+ - 🐛 Fixed path bug in local TDD provider: `screenshots/` → `current/` directory
33
+ - 🐛 Fixed API field mapping in cloud provider: API returns `result` not `status`
34
+
8
35
  ## [0.1.0] - 2025-10-18
9
36
 
10
37
  ### Added
@@ -0,0 +1,95 @@
1
+ # Vizzly Docs MCP Server
2
+
3
+ MCP server that provides Claude Code with easy access to Vizzly documentation.
4
+
5
+ ## How It Works
6
+
7
+ This server fetches documentation from the deployed `docs.vizzly.dev` site, making it easy for LLMs to:
8
+ - Browse all available docs
9
+ - Search documentation by keyword
10
+ - Retrieve full markdown content
11
+ - Understand the documentation structure
12
+
13
+ ## Tools
14
+
15
+ ### `list_docs`
16
+ List all available documentation pages with optional category filtering.
17
+
18
+ **Arguments:**
19
+ - `category` (optional): Filter by category (e.g., "Integration > CLI", "Features")
20
+
21
+ **Example:**
22
+ ```javascript
23
+ list_docs({ category: "CLI" })
24
+ ```
25
+
26
+ ### `get_doc`
27
+ Get the full markdown content of a specific documentation page.
28
+
29
+ **Arguments:**
30
+ - `path` (required): The document path (e.g., "integration/cli/overview.mdx") or slug (e.g., "integration/cli/overview")
31
+
32
+ **Example:**
33
+ ```javascript
34
+ get_doc({ path: "integration/cli/tdd-mode" })
35
+ ```
36
+
37
+ ### `search_docs`
38
+ Search documentation by keyword. Searches in titles, descriptions, and categories.
39
+
40
+ **Arguments:**
41
+ - `query` (required): Search query
42
+ - `limit` (optional): Maximum number of results (default: 10)
43
+
44
+ **Example:**
45
+ ```javascript
46
+ search_docs({ query: "parallel builds", limit: 5 })
47
+ ```
48
+
49
+ ### `get_sidebar`
50
+ Get the complete sidebar navigation structure.
51
+
52
+ **Example:**
53
+ ```javascript
54
+ get_sidebar()
55
+ ```
56
+
57
+ ## Architecture
58
+
59
+ The server works in a hybrid model:
60
+ 1. **Index** - Fetches a pre-built JSON index from `docs.vizzly.dev/api/mcp-index.json`
61
+ 2. **Content** - Fetches individual doc content on-demand from `docs.vizzly.dev/api/content/{path}`
62
+ 3. **Caching** - Index is cached for 5 minutes to minimize network requests
63
+
64
+ This approach ensures:
65
+ - Fast browsing/searching (uses cached index)
66
+ - Always up-to-date content (fetched from live site)
67
+ - Minimal network overhead
68
+ - No local file dependencies
69
+
70
+ ## Data Flow
71
+
72
+ ```
73
+ Claude Code
74
+
75
+ MCP Server (this)
76
+
77
+ docs.vizzly.dev API
78
+
79
+ Statically generated at build time (Astro)
80
+ ```
81
+
82
+ ## Development
83
+
84
+ To test the server locally:
85
+
86
+ ```bash
87
+ # The server is automatically loaded by Claude Code when the plugin is active
88
+ # Check .mcp.json for configuration
89
+ ```
90
+
91
+ ## Files
92
+
93
+ - `index.js` - Main MCP server implementation
94
+ - `docs-fetcher.js` - Utilities for fetching and searching docs
95
+ - `README.md` - This file
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Fetches documentation from docs.vizzly.dev
3
+ */
4
+
5
+ let BASE_URL = 'https://docs.vizzly.dev';
6
+ let INDEX_URL = `${BASE_URL}/api/mcp-index.json`;
7
+
8
+ /**
9
+ * Fetch the documentation index
10
+ */
11
+ export async function fetchDocsIndex() {
12
+ try {
13
+ let response = await fetch(INDEX_URL);
14
+
15
+ if (!response.ok) {
16
+ throw new Error(`Failed to fetch docs index: ${response.status} ${response.statusText}`);
17
+ }
18
+
19
+ let index = await response.json();
20
+ return index;
21
+ } catch (error) {
22
+ throw new Error(`Failed to load documentation index: ${error.message}`);
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Fetch the content of a specific document
28
+ */
29
+ export async function fetchDocContent(path) {
30
+ // Normalize path (remove leading slash, ensure it doesn't end with .md/.mdx)
31
+ let cleanPath = path.replace(/^\//, '').replace(/\.(mdx?|md)$/, '');
32
+
33
+ let contentUrl = `${BASE_URL}/api/content/${cleanPath}`;
34
+
35
+ try {
36
+ let response = await fetch(contentUrl);
37
+
38
+ if (!response.ok) {
39
+ // Try with .mdx extension if not found
40
+ if (response.status === 404 && !path.endsWith('.mdx')) {
41
+ contentUrl = `${BASE_URL}/api/content/${cleanPath}.mdx`;
42
+ response = await fetch(contentUrl);
43
+ }
44
+
45
+ if (!response.ok) {
46
+ throw new Error(`Document not found: ${path} (${response.status})`);
47
+ }
48
+ }
49
+
50
+ let content = await response.text();
51
+ return content;
52
+ } catch (error) {
53
+ throw new Error(`Failed to fetch document content: ${error.message}`);
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Search documents by query
59
+ * Simple client-side search through titles and descriptions
60
+ */
61
+ export function searchDocs(docs, query, limit = 10) {
62
+ let lowerQuery = query.toLowerCase();
63
+ let terms = lowerQuery.split(/\s+/);
64
+
65
+ let results = docs
66
+ .map(doc => {
67
+ let titleLower = doc.title.toLowerCase();
68
+ let descLower = (doc.description || '').toLowerCase();
69
+ let categoryLower = doc.category.toLowerCase();
70
+
71
+ let score = 0;
72
+
73
+ // Exact phrase match in title (highest score)
74
+ if (titleLower.includes(lowerQuery)) {
75
+ score += 10;
76
+ }
77
+
78
+ // Exact phrase match in description
79
+ if (descLower.includes(lowerQuery)) {
80
+ score += 5;
81
+ }
82
+
83
+ // Exact phrase match in category
84
+ if (categoryLower.includes(lowerQuery)) {
85
+ score += 3;
86
+ }
87
+
88
+ // Individual term matches
89
+ for (let term of terms) {
90
+ if (titleLower.includes(term)) score += 3;
91
+ if (descLower.includes(term)) score += 1;
92
+ if (categoryLower.includes(term)) score += 0.5;
93
+ }
94
+
95
+ return { doc, score };
96
+ })
97
+ .filter(result => result.score > 0)
98
+ .sort((a, b) => b.score - a.score)
99
+ .slice(0, limit);
100
+
101
+ // Normalize scores to 0-1 range
102
+ if (results.length > 0) {
103
+ let maxScore = results[0].score;
104
+ for (let result of results) {
105
+ result.score = result.score / maxScore;
106
+ }
107
+ }
108
+
109
+ return results;
110
+ }
@@ -0,0 +1,283 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Vizzly Docs MCP Server
5
+ * Provides Claude Code with easy access to Vizzly documentation
6
+ *
7
+ * This server fetches docs from the deployed docs.vizzly.dev site,
8
+ * making it easy for LLMs to navigate and retrieve documentation content.
9
+ */
10
+
11
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
12
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
13
+ import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
14
+ import { fetchDocsIndex, fetchDocContent, searchDocs } from './docs-fetcher.js';
15
+
16
+ class VizzlyDocsMCPServer {
17
+ constructor() {
18
+ this.server = new Server(
19
+ {
20
+ name: 'vizzly-docs',
21
+ version: '1.0.0'
22
+ },
23
+ {
24
+ capabilities: {
25
+ tools: {}
26
+ }
27
+ }
28
+ );
29
+
30
+ // Cache the index for the session
31
+ this.indexCache = null;
32
+ this.indexFetchTime = null;
33
+ this.CACHE_TTL = 5 * 60 * 1000; // 5 minutes
34
+
35
+ this.setupHandlers();
36
+ }
37
+
38
+ /**
39
+ * Get the docs index (with caching)
40
+ */
41
+ async getIndex() {
42
+ let now = Date.now();
43
+
44
+ if (!this.indexCache || !this.indexFetchTime || now - this.indexFetchTime > this.CACHE_TTL) {
45
+ this.indexCache = await fetchDocsIndex();
46
+ this.indexFetchTime = now;
47
+ }
48
+
49
+ return this.indexCache;
50
+ }
51
+
52
+ setupHandlers() {
53
+ // List available tools
54
+ this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
55
+ tools: [
56
+ {
57
+ name: 'list_docs',
58
+ description:
59
+ 'List all available Vizzly documentation pages. Returns title, description, category, and URL for each doc. Optionally filter by category.',
60
+ inputSchema: {
61
+ type: 'object',
62
+ properties: {
63
+ category: {
64
+ type: 'string',
65
+ description:
66
+ 'Optional category filter (e.g., "Integration > CLI", "Features"). Case-insensitive partial match.'
67
+ }
68
+ }
69
+ }
70
+ },
71
+ {
72
+ name: 'get_doc',
73
+ description:
74
+ 'Get the full markdown content of a specific documentation page. Returns the raw MDX/markdown with frontmatter. Use the path or slug from list_docs.',
75
+ inputSchema: {
76
+ type: 'object',
77
+ properties: {
78
+ path: {
79
+ type: 'string',
80
+ description:
81
+ 'The document path (e.g., "integration/cli/overview.mdx") or slug (e.g., "integration/cli/overview"). Get this from list_docs or search_docs.'
82
+ }
83
+ },
84
+ required: ['path']
85
+ }
86
+ },
87
+ {
88
+ name: 'search_docs',
89
+ description:
90
+ 'Search documentation by keyword. Searches in titles and descriptions. Returns matching docs with relevance scores.',
91
+ inputSchema: {
92
+ type: 'object',
93
+ properties: {
94
+ query: {
95
+ type: 'string',
96
+ description: 'Search query (e.g., "TDD mode", "authentication", "parallel builds")'
97
+ },
98
+ limit: {
99
+ type: 'number',
100
+ description: 'Maximum number of results to return (default: 10)',
101
+ default: 10
102
+ }
103
+ },
104
+ required: ['query']
105
+ }
106
+ },
107
+ {
108
+ name: 'get_sidebar',
109
+ description:
110
+ 'Get the complete sidebar navigation structure. Useful for understanding how docs are organized and finding related pages.',
111
+ inputSchema: {
112
+ type: 'object',
113
+ properties: {}
114
+ }
115
+ }
116
+ ]
117
+ }));
118
+
119
+ // Handle tool calls
120
+ this.server.setRequestHandler(CallToolRequestSchema, async request => {
121
+ try {
122
+ switch (request.params.name) {
123
+ case 'list_docs':
124
+ return await this.handleListDocs(request.params.arguments);
125
+
126
+ case 'get_doc':
127
+ return await this.handleGetDoc(request.params.arguments);
128
+
129
+ case 'search_docs':
130
+ return await this.handleSearchDocs(request.params.arguments);
131
+
132
+ case 'get_sidebar':
133
+ return await this.handleGetSidebar();
134
+
135
+ default:
136
+ throw new Error(`Unknown tool: ${request.params.name}`);
137
+ }
138
+ } catch (error) {
139
+ return {
140
+ content: [
141
+ {
142
+ type: 'text',
143
+ text: `Error: ${error.message}`
144
+ }
145
+ ],
146
+ isError: true
147
+ };
148
+ }
149
+ });
150
+ }
151
+
152
+ async handleListDocs(args) {
153
+ let index = await this.getIndex();
154
+ let { category } = args || {};
155
+
156
+ let docs = index.docs;
157
+
158
+ // Filter by category if provided
159
+ if (category) {
160
+ let lowerCategory = category.toLowerCase();
161
+ docs = docs.filter(doc => doc.category.toLowerCase().includes(lowerCategory));
162
+ }
163
+
164
+ // Format response
165
+ let response = `# Vizzly Documentation (${docs.length} docs)\n\n`;
166
+
167
+ if (category) {
168
+ response += `Filtered by category: "${category}"\n\n`;
169
+ }
170
+
171
+ // Group by category
172
+ let byCategory = {};
173
+ for (let doc of docs) {
174
+ if (!byCategory[doc.category]) {
175
+ byCategory[doc.category] = [];
176
+ }
177
+ byCategory[doc.category].push(doc);
178
+ }
179
+
180
+ for (let [cat, catDocs] of Object.entries(byCategory)) {
181
+ response += `## ${cat}\n\n`;
182
+ for (let doc of catDocs) {
183
+ response += `- **${doc.title}**\n`;
184
+ response += ` - Path: \`${doc.path}\`\n`;
185
+ response += ` - Slug: \`${doc.slug}\`\n`;
186
+ if (doc.description) {
187
+ response += ` - ${doc.description}\n`;
188
+ }
189
+ response += ` - URL: ${doc.url}\n\n`;
190
+ }
191
+ }
192
+
193
+ return {
194
+ content: [
195
+ {
196
+ type: 'text',
197
+ text: response
198
+ }
199
+ ]
200
+ };
201
+ }
202
+
203
+ async handleGetDoc(args) {
204
+ let { path } = args;
205
+
206
+ if (!path) {
207
+ throw new Error('path parameter is required');
208
+ }
209
+
210
+ let content = await fetchDocContent(path);
211
+
212
+ return {
213
+ content: [
214
+ {
215
+ type: 'text',
216
+ text: content
217
+ }
218
+ ]
219
+ };
220
+ }
221
+
222
+ async handleSearchDocs(args) {
223
+ let { query, limit = 10 } = args;
224
+
225
+ if (!query) {
226
+ throw new Error('query parameter is required');
227
+ }
228
+
229
+ let index = await this.getIndex();
230
+ let results = searchDocs(index.docs, query, limit);
231
+
232
+ let response = `# Search Results for "${query}"\n\n`;
233
+ response += `Found ${results.length} matching docs:\n\n`;
234
+
235
+ for (let result of results) {
236
+ response += `## ${result.doc.title}\n`;
237
+ response += `- **Category:** ${result.doc.category}\n`;
238
+ response += `- **Path:** \`${result.doc.path}\`\n`;
239
+ response += `- **Relevance:** ${Math.round(result.score * 100)}%\n`;
240
+ if (result.doc.description) {
241
+ response += `- **Description:** ${result.doc.description}\n`;
242
+ }
243
+ response += `- **URL:** ${result.doc.url}\n\n`;
244
+ }
245
+
246
+ return {
247
+ content: [
248
+ {
249
+ type: 'text',
250
+ text: response
251
+ }
252
+ ]
253
+ };
254
+ }
255
+
256
+ async handleGetSidebar() {
257
+ let index = await this.getIndex();
258
+
259
+ let response = `# Vizzly Documentation Structure\n\n`;
260
+ response += JSON.stringify(index.sidebar, null, 2);
261
+
262
+ return {
263
+ content: [
264
+ {
265
+ type: 'text',
266
+ text: response
267
+ }
268
+ ]
269
+ };
270
+ }
271
+
272
+ async run() {
273
+ let transport = new StdioServerTransport();
274
+ await this.server.connect(transport);
275
+ }
276
+ }
277
+
278
+ // Start the server
279
+ let server = new VizzlyDocsMCPServer();
280
+ server.run().catch(error => {
281
+ console.error('Server error:', error);
282
+ process.exit(1);
283
+ });
@@ -49,27 +49,43 @@ export class CloudAPIProvider {
49
49
  let { build } = data;
50
50
 
51
51
  // Calculate comparison summary
52
+ // Note: API returns 'result' field (not 'status'), and doesn't have 'has_diff'
53
+ // result can be: 'identical', 'changed', 'new', 'removed', 'error', 'missing', 'returning'
52
54
  let comparisons = build.comparisons || [];
55
+
56
+ // Calculate basic comparison summary
57
+ let changedComparisons = comparisons.filter((c) => c.result === 'changed' || (c.diff_percentage && c.diff_percentage > 0));
58
+
53
59
  let summary = {
54
60
  total: comparisons.length,
55
- new: comparisons.filter((c) => c.status === 'new').length,
56
- changed: comparisons.filter((c) => c.has_diff).length,
57
- identical: comparisons.filter((c) => !c.has_diff && c.status !== 'new').length
61
+ new: comparisons.filter((c) => c.result === 'new').length,
62
+ changed: changedComparisons.length,
63
+ identical: comparisons.filter((c) => c.result === 'identical' || (c.result !== 'new' && c.result !== 'changed' && (!c.diff_percentage || c.diff_percentage === 0))).length,
64
+ // Approval status breakdown
65
+ approval: {
66
+ pending: comparisons.filter((c) => c.approval_status === 'pending').length,
67
+ approved: comparisons.filter((c) => c.approval_status === 'approved').length,
68
+ rejected: comparisons.filter((c) => c.approval_status === 'rejected').length,
69
+ autoApproved: comparisons.filter((c) => c.approval_status === 'auto_approved').length
70
+ },
71
+ // Flaky screenshot count
72
+ flaky: comparisons.filter((c) => c.is_flaky).length
58
73
  };
59
74
 
60
- // Group comparisons by status
75
+ // Keep minimal for token efficiency - use read_comparison_details for full metadata
61
76
  let failedComparisons = comparisons
62
- .filter((c) => c.has_diff)
77
+ .filter((c) => c.result === 'changed' || (c.diff_percentage && c.diff_percentage > 0))
63
78
  .map((c) => ({
64
- name: c.name,
79
+ id: c.id,
80
+ name: c.current_name || c.name,
65
81
  diffPercentage: c.diff_percentage,
66
- currentUrl: c.current_screenshot?.original_url,
67
- baselineUrl: c.baseline_screenshot?.original_url,
68
- diffUrl: c.diff_image?.url
82
+ approvalStatus: c.approval_status,
83
+ // Include hot spot coverage % for quick triage (single number)
84
+ hotSpotCoverage: c.analysis_metadata?.hot_spot_coverage || null
69
85
  }));
70
86
 
71
87
  let newComparisons = comparisons
72
- .filter((c) => c.status === 'new')
88
+ .filter((c) => c.result === 'new')
73
89
  .map((c) => ({
74
90
  name: c.name,
75
91
  currentUrl: c.current_screenshot?.original_url
@@ -131,6 +131,15 @@ class VizzlyMCPServer {
131
131
  workingDirectory: {
132
132
  type: 'string',
133
133
  description: 'Path to project directory (optional, defaults to current directory)'
134
+ },
135
+ statusFilter: {
136
+ type: 'string',
137
+ description: 'Filter comparisons by status: "failed", "new", "passed", or "all". Defaults to "summary" (no comparisons, just counts)',
138
+ enum: ['failed', 'new', 'passed', 'all', 'summary']
139
+ },
140
+ limit: {
141
+ type: 'number',
142
+ description: 'Maximum number of comparisons to return (default: unlimited when statusFilter is set)'
134
143
  }
135
144
  }
136
145
  }
@@ -556,7 +565,11 @@ class VizzlyMCPServer {
556
565
  }
557
566
 
558
567
  case 'get_tdd_status': {
559
- let status = await this.localProvider.getTDDStatus(args.workingDirectory);
568
+ let status = await this.localProvider.getTDDStatus(
569
+ args.workingDirectory,
570
+ args.statusFilter,
571
+ args.limit
572
+ );
560
573
  return {
561
574
  content: [
562
575
  {