@browserstack/mcp-server 1.2.15-beta.1 → 1.2.15-beta.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 (170) hide show
  1. package/dist/lib/percy-api/auth.d.ts +41 -0
  2. package/dist/lib/percy-api/auth.js +96 -0
  3. package/dist/lib/percy-api/cache.d.ts +28 -0
  4. package/dist/lib/percy-api/cache.js +48 -0
  5. package/dist/lib/percy-api/client.d.ts +69 -0
  6. package/dist/lib/percy-api/client.js +275 -0
  7. package/dist/lib/percy-api/errors.d.ts +15 -0
  8. package/dist/lib/percy-api/errors.js +52 -0
  9. package/dist/lib/percy-api/formatter.d.ts +16 -0
  10. package/dist/lib/percy-api/formatter.js +344 -0
  11. package/dist/lib/percy-api/percy-auth.d.ts +43 -0
  12. package/dist/lib/percy-api/percy-auth.js +137 -0
  13. package/dist/lib/percy-api/percy-error-handler.d.ts +24 -0
  14. package/dist/lib/percy-api/percy-error-handler.js +302 -0
  15. package/dist/lib/percy-api/percy-session.d.ts +42 -0
  16. package/dist/lib/percy-api/percy-session.js +87 -0
  17. package/dist/lib/percy-api/polling.d.ts +26 -0
  18. package/dist/lib/percy-api/polling.js +42 -0
  19. package/dist/lib/percy-api/types.d.ts +56 -0
  20. package/dist/lib/percy-api/types.js +76 -0
  21. package/dist/server-factory.js +4 -0
  22. package/dist/tools/percy-mcp/advanced/branchline-operations.d.ts +16 -0
  23. package/dist/tools/percy-mcp/advanced/branchline-operations.js +81 -0
  24. package/dist/tools/percy-mcp/advanced/manage-variants.d.ts +16 -0
  25. package/dist/tools/percy-mcp/advanced/manage-variants.js +155 -0
  26. package/dist/tools/percy-mcp/advanced/manage-visual-monitoring.d.ts +16 -0
  27. package/dist/tools/percy-mcp/advanced/manage-visual-monitoring.js +171 -0
  28. package/dist/tools/percy-mcp/auth/auth-status.d.ts +3 -0
  29. package/dist/tools/percy-mcp/auth/auth-status.js +131 -0
  30. package/dist/tools/percy-mcp/core/approve-build.d.ts +14 -0
  31. package/dist/tools/percy-mcp/core/approve-build.js +97 -0
  32. package/dist/tools/percy-mcp/core/get-build-items.d.ts +13 -0
  33. package/dist/tools/percy-mcp/core/get-build-items.js +65 -0
  34. package/dist/tools/percy-mcp/core/get-build.d.ts +10 -0
  35. package/dist/tools/percy-mcp/core/get-build.js +16 -0
  36. package/dist/tools/percy-mcp/core/get-comparison.d.ts +11 -0
  37. package/dist/tools/percy-mcp/core/get-comparison.js +59 -0
  38. package/dist/tools/percy-mcp/core/get-snapshot.d.ts +10 -0
  39. package/dist/tools/percy-mcp/core/get-snapshot.js +40 -0
  40. package/dist/tools/percy-mcp/core/list-builds.d.ts +14 -0
  41. package/dist/tools/percy-mcp/core/list-builds.js +45 -0
  42. package/dist/tools/percy-mcp/core/list-projects.d.ts +12 -0
  43. package/dist/tools/percy-mcp/core/list-projects.js +51 -0
  44. package/dist/tools/percy-mcp/creation/create-app-snapshot.d.ts +12 -0
  45. package/dist/tools/percy-mcp/creation/create-app-snapshot.js +29 -0
  46. package/dist/tools/percy-mcp/creation/create-build.d.ts +19 -0
  47. package/dist/tools/percy-mcp/creation/create-build.js +68 -0
  48. package/dist/tools/percy-mcp/creation/create-comparison.d.ts +18 -0
  49. package/dist/tools/percy-mcp/creation/create-comparison.js +90 -0
  50. package/dist/tools/percy-mcp/creation/create-snapshot.d.ts +17 -0
  51. package/dist/tools/percy-mcp/creation/create-snapshot.js +99 -0
  52. package/dist/tools/percy-mcp/creation/finalize-build.d.ts +12 -0
  53. package/dist/tools/percy-mcp/creation/finalize-build.js +33 -0
  54. package/dist/tools/percy-mcp/creation/finalize-comparison.d.ts +10 -0
  55. package/dist/tools/percy-mcp/creation/finalize-comparison.js +16 -0
  56. package/dist/tools/percy-mcp/creation/finalize-snapshot.d.ts +12 -0
  57. package/dist/tools/percy-mcp/creation/finalize-snapshot.js +33 -0
  58. package/dist/tools/percy-mcp/creation/upload-resource.d.ts +15 -0
  59. package/dist/tools/percy-mcp/creation/upload-resource.js +43 -0
  60. package/dist/tools/percy-mcp/creation/upload-tile.d.ts +11 -0
  61. package/dist/tools/percy-mcp/creation/upload-tile.js +53 -0
  62. package/dist/tools/percy-mcp/diagnostics/analyze-logs-realtime.d.ts +13 -0
  63. package/dist/tools/percy-mcp/diagnostics/analyze-logs-realtime.js +65 -0
  64. package/dist/tools/percy-mcp/diagnostics/get-build-logs.d.ts +17 -0
  65. package/dist/tools/percy-mcp/diagnostics/get-build-logs.js +74 -0
  66. package/dist/tools/percy-mcp/diagnostics/get-network-logs.d.ts +5 -0
  67. package/dist/tools/percy-mcp/diagnostics/get-network-logs.js +21 -0
  68. package/dist/tools/percy-mcp/diagnostics/get-suggestions.d.ts +7 -0
  69. package/dist/tools/percy-mcp/diagnostics/get-suggestions.js +24 -0
  70. package/dist/tools/percy-mcp/index.d.ts +36 -0
  71. package/dist/tools/percy-mcp/index.js +1137 -0
  72. package/dist/tools/percy-mcp/intelligence/get-ai-analysis.d.ts +15 -0
  73. package/dist/tools/percy-mcp/intelligence/get-ai-analysis.js +166 -0
  74. package/dist/tools/percy-mcp/intelligence/get-ai-quota.d.ts +9 -0
  75. package/dist/tools/percy-mcp/intelligence/get-ai-quota.js +73 -0
  76. package/dist/tools/percy-mcp/intelligence/get-build-summary.d.ts +11 -0
  77. package/dist/tools/percy-mcp/intelligence/get-build-summary.js +78 -0
  78. package/dist/tools/percy-mcp/intelligence/get-rca.d.ts +6 -0
  79. package/dist/tools/percy-mcp/intelligence/get-rca.js +153 -0
  80. package/dist/tools/percy-mcp/intelligence/suggest-prompt.d.ts +15 -0
  81. package/dist/tools/percy-mcp/intelligence/suggest-prompt.js +86 -0
  82. package/dist/tools/percy-mcp/intelligence/trigger-ai-recompute.d.ts +16 -0
  83. package/dist/tools/percy-mcp/intelligence/trigger-ai-recompute.js +64 -0
  84. package/dist/tools/percy-mcp/management/create-project.d.ts +14 -0
  85. package/dist/tools/percy-mcp/management/create-project.js +52 -0
  86. package/dist/tools/percy-mcp/management/get-usage-stats.d.ts +12 -0
  87. package/dist/tools/percy-mcp/management/get-usage-stats.js +61 -0
  88. package/dist/tools/percy-mcp/management/manage-browser-targets.d.ts +12 -0
  89. package/dist/tools/percy-mcp/management/manage-browser-targets.js +136 -0
  90. package/dist/tools/percy-mcp/management/manage-comments.d.ts +14 -0
  91. package/dist/tools/percy-mcp/management/manage-comments.js +147 -0
  92. package/dist/tools/percy-mcp/management/manage-ignored-regions.d.ts +18 -0
  93. package/dist/tools/percy-mcp/management/manage-ignored-regions.js +182 -0
  94. package/dist/tools/percy-mcp/management/manage-project-settings.d.ts +16 -0
  95. package/dist/tools/percy-mcp/management/manage-project-settings.js +97 -0
  96. package/dist/tools/percy-mcp/management/manage-tokens.d.ts +14 -0
  97. package/dist/tools/percy-mcp/management/manage-tokens.js +90 -0
  98. package/dist/tools/percy-mcp/management/manage-webhooks.d.ts +15 -0
  99. package/dist/tools/percy-mcp/management/manage-webhooks.js +180 -0
  100. package/dist/tools/percy-mcp/v2/auth-status.d.ts +3 -0
  101. package/dist/tools/percy-mcp/v2/auth-status.js +80 -0
  102. package/dist/tools/percy-mcp/v2/clone-build.d.ts +24 -0
  103. package/dist/tools/percy-mcp/v2/clone-build.js +539 -0
  104. package/dist/tools/percy-mcp/v2/create-app-build.d.ts +28 -0
  105. package/dist/tools/percy-mcp/v2/create-app-build.js +442 -0
  106. package/dist/tools/percy-mcp/v2/create-build.d.ts +16 -0
  107. package/dist/tools/percy-mcp/v2/create-build.js +601 -0
  108. package/dist/tools/percy-mcp/v2/create-project.d.ts +8 -0
  109. package/dist/tools/percy-mcp/v2/create-project.js +33 -0
  110. package/dist/tools/percy-mcp/v2/discover-urls.d.ts +7 -0
  111. package/dist/tools/percy-mcp/v2/discover-urls.js +38 -0
  112. package/dist/tools/percy-mcp/v2/figma-baseline.d.ts +7 -0
  113. package/dist/tools/percy-mcp/v2/figma-baseline.js +18 -0
  114. package/dist/tools/percy-mcp/v2/figma-build.d.ts +7 -0
  115. package/dist/tools/percy-mcp/v2/figma-build.js +39 -0
  116. package/dist/tools/percy-mcp/v2/figma-link.d.ts +6 -0
  117. package/dist/tools/percy-mcp/v2/figma-link.js +27 -0
  118. package/dist/tools/percy-mcp/v2/get-ai-summary.d.ts +5 -0
  119. package/dist/tools/percy-mcp/v2/get-ai-summary.js +109 -0
  120. package/dist/tools/percy-mcp/v2/get-build-detail.d.ts +22 -0
  121. package/dist/tools/percy-mcp/v2/get-build-detail.js +567 -0
  122. package/dist/tools/percy-mcp/v2/get-builds.d.ts +8 -0
  123. package/dist/tools/percy-mcp/v2/get-builds.js +63 -0
  124. package/dist/tools/percy-mcp/v2/get-comparison.d.ts +5 -0
  125. package/dist/tools/percy-mcp/v2/get-comparison.js +94 -0
  126. package/dist/tools/percy-mcp/v2/get-devices.d.ts +5 -0
  127. package/dist/tools/percy-mcp/v2/get-devices.js +33 -0
  128. package/dist/tools/percy-mcp/v2/get-insights.d.ts +7 -0
  129. package/dist/tools/percy-mcp/v2/get-insights.js +52 -0
  130. package/dist/tools/percy-mcp/v2/get-projects.d.ts +6 -0
  131. package/dist/tools/percy-mcp/v2/get-projects.js +41 -0
  132. package/dist/tools/percy-mcp/v2/get-snapshot.d.ts +5 -0
  133. package/dist/tools/percy-mcp/v2/get-snapshot.js +96 -0
  134. package/dist/tools/percy-mcp/v2/get-test-case-history.d.ts +5 -0
  135. package/dist/tools/percy-mcp/v2/get-test-case-history.js +20 -0
  136. package/dist/tools/percy-mcp/v2/get-test-cases.d.ts +6 -0
  137. package/dist/tools/percy-mcp/v2/get-test-cases.js +36 -0
  138. package/dist/tools/percy-mcp/v2/index.d.ts +35 -0
  139. package/dist/tools/percy-mcp/v2/index.js +544 -0
  140. package/dist/tools/percy-mcp/v2/list-integrations.d.ts +5 -0
  141. package/dist/tools/percy-mcp/v2/list-integrations.js +41 -0
  142. package/dist/tools/percy-mcp/v2/manage-domains.d.ts +8 -0
  143. package/dist/tools/percy-mcp/v2/manage-domains.js +33 -0
  144. package/dist/tools/percy-mcp/v2/manage-insights-email.d.ts +8 -0
  145. package/dist/tools/percy-mcp/v2/manage-insights-email.js +49 -0
  146. package/dist/tools/percy-mcp/v2/manage-usage-alerts.d.ts +10 -0
  147. package/dist/tools/percy-mcp/v2/manage-usage-alerts.js +43 -0
  148. package/dist/tools/percy-mcp/v2/migrate-integrations.d.ts +6 -0
  149. package/dist/tools/percy-mcp/v2/migrate-integrations.js +20 -0
  150. package/dist/tools/percy-mcp/v2/preview-comparison.d.ts +5 -0
  151. package/dist/tools/percy-mcp/v2/preview-comparison.js +17 -0
  152. package/dist/tools/percy-mcp/v2/search-build-items.d.ts +12 -0
  153. package/dist/tools/percy-mcp/v2/search-build-items.js +45 -0
  154. package/dist/tools/percy-mcp/workflows/auto-triage.d.ts +7 -0
  155. package/dist/tools/percy-mcp/workflows/auto-triage.js +82 -0
  156. package/dist/tools/percy-mcp/workflows/clone-build.d.ts +22 -0
  157. package/dist/tools/percy-mcp/workflows/clone-build.js +414 -0
  158. package/dist/tools/percy-mcp/workflows/create-percy-build.d.ts +32 -0
  159. package/dist/tools/percy-mcp/workflows/create-percy-build.js +434 -0
  160. package/dist/tools/percy-mcp/workflows/debug-failed-build.d.ts +5 -0
  161. package/dist/tools/percy-mcp/workflows/debug-failed-build.js +122 -0
  162. package/dist/tools/percy-mcp/workflows/diff-explain.d.ts +6 -0
  163. package/dist/tools/percy-mcp/workflows/diff-explain.js +147 -0
  164. package/dist/tools/percy-mcp/workflows/pr-visual-report.d.ts +8 -0
  165. package/dist/tools/percy-mcp/workflows/pr-visual-report.js +184 -0
  166. package/dist/tools/percy-mcp/workflows/run-tests.d.ts +17 -0
  167. package/dist/tools/percy-mcp/workflows/run-tests.js +107 -0
  168. package/dist/tools/percy-mcp/workflows/snapshot-urls.d.ts +18 -0
  169. package/dist/tools/percy-mcp/workflows/snapshot-urls.js +197 -0
  170. package/package.json +3 -2
@@ -0,0 +1,302 @@
1
+ /**
2
+ * Shared Percy error handler — turns raw API errors into helpful guidance.
3
+ *
4
+ * Instead of showing "403 Forbidden" or "404 Not Found", returns:
5
+ * - What went wrong
6
+ * - What the correct input looks like
7
+ * - Suggested next steps
8
+ */
9
+ export function handlePercyToolError(error, toolHelp, args) {
10
+ const message = error instanceof Error ? error.message : String(error);
11
+ let output = `## Error: ${toolHelp.name}\n\n`;
12
+ // Parse the error type
13
+ if (message.includes("401") || message.includes("Unauthorized")) {
14
+ output += `**Authentication failed.** Your BrowserStack credentials may be invalid or expired.\n\n`;
15
+ output += `Check with: \`Use percy_auth_status\`\n`;
16
+ }
17
+ else if (message.includes("403") || message.includes("Forbidden")) {
18
+ output += `**Access denied.** Your credentials don't have permission for this operation.\n\n`;
19
+ output += `This usually means:\n`;
20
+ output += `- The ID you provided doesn't belong to your organization\n`;
21
+ output += `- Your account doesn't have access to this feature\n`;
22
+ }
23
+ else if (message.includes("404") || message.includes("Not Found")) {
24
+ output += `**Not found.** The ID or slug you provided doesn't exist.\n\n`;
25
+ // Show what was passed
26
+ const passedArgs = Object.entries(args)
27
+ .filter(([, v]) => v != null && v !== "")
28
+ .map(([k, v]) => `- \`${k}\`: \`${String(v)}\``)
29
+ .join("\n");
30
+ if (passedArgs) {
31
+ output += `You provided:\n${passedArgs}\n\n`;
32
+ }
33
+ output += `Double-check the ID/slug is correct.\n`;
34
+ }
35
+ else if (message.includes("422") || message.includes("Unprocessable")) {
36
+ output += `**Invalid input.** The parameters you provided aren't valid.\n\n`;
37
+ }
38
+ else if (message.includes("429") || message.includes("Rate")) {
39
+ output += `**Rate limited.** Too many requests. Wait a moment and try again.\n`;
40
+ return { content: [{ type: "text", text: output }], isError: true };
41
+ }
42
+ else if (message.includes("500") || message.includes("Internal Server")) {
43
+ output += `**Percy API error.** The server returned an internal error. This is usually temporary.\n\n`;
44
+ output += `Try again in a moment. If it persists, the endpoint may not be available for your account.\n`;
45
+ }
46
+ else {
47
+ output += `**Error:** ${message}\n\n`;
48
+ }
49
+ // Show correct usage
50
+ output += `\n### Correct Usage\n\n`;
51
+ output += `**${toolHelp.description}**\n\n`;
52
+ output += `| Parameter | Required | Description | Example |\n|---|---|---|---|\n`;
53
+ toolHelp.params.forEach((p) => {
54
+ output += `| \`${p.name}\` | ${p.required ? "Yes" : "No"} | ${p.description} | \`${p.example}\` |\n`;
55
+ });
56
+ if (toolHelp.examples.length > 0) {
57
+ output += `\n### Examples\n\n`;
58
+ toolHelp.examples.forEach((ex) => {
59
+ output += `\`\`\`\n${ex}\n\`\`\`\n\n`;
60
+ });
61
+ }
62
+ // Suggest discovery tools
63
+ output += `### How to find the right IDs\n\n`;
64
+ output += `- **Project slug:** \`Use percy_get_projects\`\n`;
65
+ output += `- **Build ID:** \`Use percy_get_builds with project_slug "org/project"\`\n`;
66
+ output += `- **Snapshot ID:** \`Use percy_get_build with build_id "123" and detail "snapshots"\`\n`;
67
+ output += `- **Comparison ID:** \`Use percy_get_snapshot with snapshot_id "456"\`\n`;
68
+ return { content: [{ type: "text", text: output }], isError: true };
69
+ }
70
+ // ── Pre-defined tool help for each tool ─────────────────────────────────────
71
+ export const TOOL_HELP = {
72
+ percy_get_build: {
73
+ name: "percy_get_build",
74
+ description: "Get build details with different views",
75
+ params: [
76
+ {
77
+ name: "build_id",
78
+ required: true,
79
+ description: "Percy build ID (numeric)",
80
+ example: "48436286",
81
+ },
82
+ {
83
+ name: "detail",
84
+ required: false,
85
+ description: "View type",
86
+ example: "overview",
87
+ },
88
+ {
89
+ name: "comparison_id",
90
+ required: false,
91
+ description: "For rca/network detail",
92
+ example: "4391856176",
93
+ },
94
+ ],
95
+ examples: [
96
+ 'Use percy_get_build with build_id "48436286"',
97
+ 'Use percy_get_build with build_id "48436286" and detail "ai_summary"',
98
+ 'Use percy_get_build with build_id "48436286" and detail "changes"',
99
+ ],
100
+ },
101
+ percy_get_snapshot: {
102
+ name: "percy_get_snapshot",
103
+ description: "Get snapshot with all comparisons and AI analysis",
104
+ params: [
105
+ {
106
+ name: "snapshot_id",
107
+ required: true,
108
+ description: "Percy snapshot ID (numeric)",
109
+ example: "2576885624",
110
+ },
111
+ ],
112
+ examples: ['Use percy_get_snapshot with snapshot_id "2576885624"'],
113
+ },
114
+ percy_get_comparison: {
115
+ name: "percy_get_comparison",
116
+ description: "Get comparison with AI change descriptions and image URLs",
117
+ params: [
118
+ {
119
+ name: "comparison_id",
120
+ required: true,
121
+ description: "Percy comparison ID (numeric)",
122
+ example: "4391856176",
123
+ },
124
+ ],
125
+ examples: ['Use percy_get_comparison with comparison_id "4391856176"'],
126
+ },
127
+ percy_get_builds: {
128
+ name: "percy_get_builds",
129
+ description: "List builds for a project",
130
+ params: [
131
+ {
132
+ name: "project_slug",
133
+ required: false,
134
+ description: "Project slug from percy_get_projects",
135
+ example: "9560f98d/my-project-abc123",
136
+ },
137
+ {
138
+ name: "branch",
139
+ required: false,
140
+ description: "Filter by branch",
141
+ example: "main",
142
+ },
143
+ {
144
+ name: "state",
145
+ required: false,
146
+ description: "Filter by state",
147
+ example: "finished",
148
+ },
149
+ ],
150
+ examples: [
151
+ 'Use percy_get_builds with project_slug "9560f98d/my-project-abc123"',
152
+ "Use percy_get_projects (to find project slugs first)",
153
+ ],
154
+ },
155
+ percy_get_projects: {
156
+ name: "percy_get_projects",
157
+ description: "List all Percy projects",
158
+ params: [
159
+ {
160
+ name: "search",
161
+ required: false,
162
+ description: "Search by name",
163
+ example: "my-app",
164
+ },
165
+ ],
166
+ examples: [
167
+ "Use percy_get_projects",
168
+ 'Use percy_get_projects with search "dashboard"',
169
+ ],
170
+ },
171
+ percy_create_build: {
172
+ name: "percy_create_build",
173
+ description: "Create a Percy build with snapshots",
174
+ params: [
175
+ {
176
+ name: "project_name",
177
+ required: true,
178
+ description: "Project name",
179
+ example: "my-app",
180
+ },
181
+ {
182
+ name: "urls",
183
+ required: false,
184
+ description: "URLs to snapshot",
185
+ example: "http://localhost:3000",
186
+ },
187
+ {
188
+ name: "screenshots_dir",
189
+ required: false,
190
+ description: "Screenshot directory",
191
+ example: "./screenshots",
192
+ },
193
+ {
194
+ name: "test_command",
195
+ required: false,
196
+ description: "Test command",
197
+ example: "npx cypress run",
198
+ },
199
+ ],
200
+ examples: [
201
+ 'Use percy_create_build with project_name "my-app" and urls "http://localhost:3000"',
202
+ ],
203
+ },
204
+ percy_create_project: {
205
+ name: "percy_create_project",
206
+ description: "Create or get a Percy project",
207
+ params: [
208
+ {
209
+ name: "name",
210
+ required: true,
211
+ description: "Project name",
212
+ example: "my-app",
213
+ },
214
+ {
215
+ name: "type",
216
+ required: false,
217
+ description: "web or automate",
218
+ example: "web",
219
+ },
220
+ ],
221
+ examples: ['Use percy_create_project with name "my-app"'],
222
+ },
223
+ percy_clone_build: {
224
+ name: "percy_clone_build",
225
+ description: "Clone snapshots from one build to another project",
226
+ params: [
227
+ {
228
+ name: "source_build_id",
229
+ required: true,
230
+ description: "Build ID to clone from",
231
+ example: "48436286",
232
+ },
233
+ {
234
+ name: "target_project_name",
235
+ required: true,
236
+ description: "Target project name",
237
+ example: "my-project",
238
+ },
239
+ ],
240
+ examples: [
241
+ 'Use percy_clone_build with source_build_id "48436286" and target_project_name "my-project"',
242
+ ],
243
+ },
244
+ percy_create_app_build: {
245
+ name: "percy_create_app_build",
246
+ description: "Create an App Percy BYOS build from device screenshots",
247
+ params: [
248
+ {
249
+ name: "project_name",
250
+ required: true,
251
+ description: "App Percy project name",
252
+ example: "my-mobile-app",
253
+ },
254
+ {
255
+ name: "resources_dir",
256
+ required: true,
257
+ description: "Path to resources directory with device folders",
258
+ example: "./resources",
259
+ },
260
+ {
261
+ name: "branch",
262
+ required: false,
263
+ description: "Git branch (auto-detected)",
264
+ example: "main",
265
+ },
266
+ {
267
+ name: "test_case",
268
+ required: false,
269
+ description: "Test case name for all snapshots",
270
+ example: "Login Flow",
271
+ },
272
+ ],
273
+ examples: [
274
+ 'Use percy_create_app_build with project_name "my-mobile-app" and resources_dir "./resources"',
275
+ ],
276
+ },
277
+ percy_get_insights: {
278
+ name: "percy_get_insights",
279
+ description: "Get testing health metrics",
280
+ params: [
281
+ {
282
+ name: "org_slug",
283
+ required: true,
284
+ description: "Organization slug or ID",
285
+ example: "9560f98d",
286
+ },
287
+ {
288
+ name: "period",
289
+ required: false,
290
+ description: "Time period",
291
+ example: "last_30_days",
292
+ },
293
+ {
294
+ name: "product",
295
+ required: false,
296
+ description: "web or app",
297
+ example: "web",
298
+ },
299
+ ],
300
+ examples: ['Use percy_get_insights with org_slug "9560f98d"'],
301
+ },
302
+ };
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Percy Session — In-memory state that persists across tool calls.
3
+ *
4
+ * Stores active project token, build context, and org info so
5
+ * subsequent tool calls get richer context automatically.
6
+ */
7
+ export interface PercySessionState {
8
+ projectName?: string;
9
+ projectToken?: string;
10
+ projectSlug?: string;
11
+ projectId?: string;
12
+ projectType?: string;
13
+ buildId?: string;
14
+ buildNumber?: string;
15
+ buildUrl?: string;
16
+ buildBranch?: string;
17
+ orgSlug?: string;
18
+ orgId?: string;
19
+ }
20
+ export declare function setActiveProject(opts: {
21
+ name: string;
22
+ token: string;
23
+ slug?: string;
24
+ id?: string;
25
+ type?: string;
26
+ }): void;
27
+ export declare function setActiveBuild(opts: {
28
+ id: string;
29
+ number?: string;
30
+ url?: string;
31
+ branch?: string;
32
+ }): void;
33
+ export declare function setOrg(opts: {
34
+ slug?: string;
35
+ id?: string;
36
+ }): void;
37
+ export declare function getSession(): PercySessionState;
38
+ export declare function getActiveToken(): string | undefined;
39
+ export declare function getActiveBuildId(): string | undefined;
40
+ export declare function formatActiveProject(): string;
41
+ export declare function formatActiveBuild(): string;
42
+ export declare function formatSessionSummary(): string;
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Percy Session — In-memory state that persists across tool calls.
3
+ *
4
+ * Stores active project token, build context, and org info so
5
+ * subsequent tool calls get richer context automatically.
6
+ */
7
+ const session = {};
8
+ // ── Setters ─────────────────────────────────────────────────────────────────
9
+ export function setActiveProject(opts) {
10
+ session.projectName = opts.name;
11
+ session.projectToken = opts.token;
12
+ if (opts.slug)
13
+ session.projectSlug = opts.slug;
14
+ if (opts.id)
15
+ session.projectId = opts.id;
16
+ if (opts.type)
17
+ session.projectType = opts.type;
18
+ }
19
+ export function setActiveBuild(opts) {
20
+ session.buildId = opts.id;
21
+ if (opts.number)
22
+ session.buildNumber = opts.number;
23
+ if (opts.url)
24
+ session.buildUrl = opts.url;
25
+ if (opts.branch)
26
+ session.buildBranch = opts.branch;
27
+ }
28
+ export function setOrg(opts) {
29
+ if (opts.slug)
30
+ session.orgSlug = opts.slug;
31
+ if (opts.id)
32
+ session.orgId = opts.id;
33
+ }
34
+ // ── Getters ─────────────────────────────────────────────────────────────────
35
+ export function getSession() {
36
+ return { ...session };
37
+ }
38
+ export function getActiveToken() {
39
+ return session.projectToken;
40
+ }
41
+ export function getActiveBuildId() {
42
+ return session.buildId;
43
+ }
44
+ // ── Formatters (append to tool output) ──────────────────────────────────────
45
+ export function formatActiveProject() {
46
+ if (!session.projectName)
47
+ return "";
48
+ const masked = session.projectToken
49
+ ? `${session.projectToken.slice(0, 8)}...${session.projectToken.slice(-4)}`
50
+ : "—";
51
+ let out = `\n### Active Project\n\n`;
52
+ out += `| | |\n|---|---|\n`;
53
+ out += `| **Project** | ${session.projectName} |\n`;
54
+ out += `| **Token** | \`${masked}\` |\n`;
55
+ if (session.projectType)
56
+ out += `| **Type** | ${session.projectType} |\n`;
57
+ if (session.projectSlug)
58
+ out += `| **Slug** | ${session.projectSlug} |\n`;
59
+ return out;
60
+ }
61
+ export function formatActiveBuild() {
62
+ if (!session.buildId)
63
+ return "";
64
+ let out = `\n### Active Build\n\n`;
65
+ out += `| | |\n|---|---|\n`;
66
+ out += `| **Build ID** | ${session.buildId} |\n`;
67
+ if (session.buildNumber)
68
+ out += `| **Build #** | ${session.buildNumber} |\n`;
69
+ if (session.buildUrl)
70
+ out += `| **URL** | ${session.buildUrl} |\n`;
71
+ if (session.buildBranch)
72
+ out += `| **Branch** | ${session.buildBranch} |\n`;
73
+ return out;
74
+ }
75
+ export function formatSessionSummary() {
76
+ const parts = [];
77
+ if (session.projectName) {
78
+ const masked = session.projectToken
79
+ ? `****${session.projectToken.slice(-4)}`
80
+ : "";
81
+ parts.push(`**Project:** ${session.projectName} (${masked})`);
82
+ }
83
+ if (session.buildId) {
84
+ parts.push(`**Build:** #${session.buildNumber || session.buildId}${session.buildUrl ? ` — ${session.buildUrl}` : ""}`);
85
+ }
86
+ return parts.length > 0 ? parts.join(" | ") : "";
87
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Exponential backoff polling utility for Percy API.
3
+ *
4
+ * Used when waiting for async operations to complete (e.g., build processing,
5
+ * AI analysis finishing). Returns null on timeout rather than throwing.
6
+ */
7
+ export interface PollOptions {
8
+ /** Initial delay between polls in milliseconds. Default: 500 */
9
+ initialDelayMs?: number;
10
+ /** Maximum delay between polls in milliseconds. Default: 5000 */
11
+ maxDelayMs?: number;
12
+ /** Total timeout in milliseconds. Default: 120000 (2 minutes) */
13
+ maxTimeoutMs?: number;
14
+ /** Optional callback invoked before each poll attempt. */
15
+ onPoll?: (attempt: number) => void;
16
+ }
17
+ /**
18
+ * Polls `fn` with exponential backoff until it returns `{ done: true }`.
19
+ *
20
+ * Backoff schedule: initialDelay → 2x → 4x → ... capped at maxDelay.
21
+ * Returns the result when done, or null if the timeout is exceeded.
22
+ */
23
+ export declare function pollUntil<T>(fn: () => Promise<{
24
+ done: boolean;
25
+ result?: T;
26
+ }>, options?: PollOptions): Promise<T | null>;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Exponential backoff polling utility for Percy API.
3
+ *
4
+ * Used when waiting for async operations to complete (e.g., build processing,
5
+ * AI analysis finishing). Returns null on timeout rather than throwing.
6
+ */
7
+ /**
8
+ * Polls `fn` with exponential backoff until it returns `{ done: true }`.
9
+ *
10
+ * Backoff schedule: initialDelay → 2x → 4x → ... capped at maxDelay.
11
+ * Returns the result when done, or null if the timeout is exceeded.
12
+ */
13
+ export async function pollUntil(fn, options) {
14
+ const initialDelayMs = options?.initialDelayMs ?? 500;
15
+ const maxDelayMs = options?.maxDelayMs ?? 5_000;
16
+ const maxTimeoutMs = options?.maxTimeoutMs ?? 120_000;
17
+ const onPoll = options?.onPoll;
18
+ const startTime = Date.now();
19
+ let delay = initialDelayMs;
20
+ let attempt = 0;
21
+ while (Date.now() - startTime < maxTimeoutMs) {
22
+ attempt++;
23
+ if (onPoll) {
24
+ onPoll(attempt);
25
+ }
26
+ const response = await fn();
27
+ if (response.done) {
28
+ return response.result ?? null;
29
+ }
30
+ // Check if waiting another cycle would exceed the timeout
31
+ if (Date.now() - startTime + delay >= maxTimeoutMs) {
32
+ break;
33
+ }
34
+ await sleep(delay);
35
+ delay = Math.min(delay * 2, maxDelayMs);
36
+ }
37
+ // Timeout exceeded
38
+ return null;
39
+ }
40
+ function sleep(ms) {
41
+ return new Promise((resolve) => setTimeout(resolve, ms));
42
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Percy API Zod schemas and inferred TypeScript types.
3
+ *
4
+ * All schemas use `.passthrough()` to allow extra fields from the API
5
+ * without throwing validation errors. This ensures forward compatibility
6
+ * as the Percy API evolves.
7
+ */
8
+ import { z } from "zod";
9
+ export declare const PercyBuildSchema: z.ZodObject<{
10
+ id: z.ZodString;
11
+ type: z.ZodOptional<z.ZodLiteral<"builds">>;
12
+ state: z.ZodString;
13
+ branch: z.ZodNullable<z.ZodString>;
14
+ buildNumber: z.ZodNullable<z.ZodNumber>;
15
+ reviewState: z.ZodNullable<z.ZodString>;
16
+ reviewStateReason: z.ZodNullable<z.ZodString>;
17
+ totalSnapshots: z.ZodNullable<z.ZodNumber>;
18
+ totalComparisons: z.ZodNullable<z.ZodNumber>;
19
+ totalComparisonsDiff: z.ZodNullable<z.ZodNumber>;
20
+ failedSnapshotsCount: z.ZodNullable<z.ZodNumber>;
21
+ failureReason: z.ZodNullable<z.ZodString>;
22
+ createdAt: z.ZodNullable<z.ZodString>;
23
+ finishedAt: z.ZodNullable<z.ZodString>;
24
+ aiDetails: z.ZodNullable<z.ZodAny>;
25
+ errorBuckets: z.ZodNullable<z.ZodArray<z.ZodAny>>;
26
+ }, z.core.$loose>;
27
+ export type PercyBuild = z.infer<typeof PercyBuildSchema>;
28
+ export declare const PercyComparisonSchema: z.ZodObject<{
29
+ id: z.ZodString;
30
+ state: z.ZodNullable<z.ZodString>;
31
+ width: z.ZodNullable<z.ZodNumber>;
32
+ diffRatio: z.ZodNullable<z.ZodNumber>;
33
+ aiDiffRatio: z.ZodNullable<z.ZodNumber>;
34
+ aiProcessingState: z.ZodNullable<z.ZodString>;
35
+ aiDetails: z.ZodNullable<z.ZodAny>;
36
+ appliedRegions: z.ZodNullable<z.ZodArray<z.ZodAny>>;
37
+ }, z.core.$loose>;
38
+ export type PercyComparison = z.infer<typeof PercyComparisonSchema>;
39
+ export declare const PercySnapshotSchema: z.ZodObject<{
40
+ id: z.ZodString;
41
+ name: z.ZodNullable<z.ZodString>;
42
+ reviewState: z.ZodNullable<z.ZodString>;
43
+ reviewStateReason: z.ZodNullable<z.ZodString>;
44
+ }, z.core.$loose>;
45
+ export type PercySnapshot = z.infer<typeof PercySnapshotSchema>;
46
+ export declare const PercyProjectSchema: z.ZodObject<{
47
+ id: z.ZodString;
48
+ name: z.ZodNullable<z.ZodString>;
49
+ slug: z.ZodNullable<z.ZodString>;
50
+ }, z.core.$loose>;
51
+ export type PercyProject = z.infer<typeof PercyProjectSchema>;
52
+ export declare const PercyBuildSummarySchema: z.ZodObject<{
53
+ id: z.ZodString;
54
+ summary: z.ZodNullable<z.ZodString>;
55
+ }, z.core.$loose>;
56
+ export type PercyBuildSummary = z.infer<typeof PercyBuildSummarySchema>;
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Percy API Zod schemas and inferred TypeScript types.
3
+ *
4
+ * All schemas use `.passthrough()` to allow extra fields from the API
5
+ * without throwing validation errors. This ensures forward compatibility
6
+ * as the Percy API evolves.
7
+ */
8
+ import { z } from "zod";
9
+ // ---------------------------------------------------------------------------
10
+ // Build
11
+ // ---------------------------------------------------------------------------
12
+ export const PercyBuildSchema = z
13
+ .object({
14
+ id: z.string(),
15
+ type: z.literal("builds").optional(),
16
+ state: z.string(),
17
+ branch: z.string().nullable(),
18
+ buildNumber: z.number().nullable(),
19
+ reviewState: z.string().nullable(),
20
+ reviewStateReason: z.string().nullable(),
21
+ totalSnapshots: z.number().nullable(),
22
+ totalComparisons: z.number().nullable(),
23
+ totalComparisonsDiff: z.number().nullable(),
24
+ failedSnapshotsCount: z.number().nullable(),
25
+ failureReason: z.string().nullable(),
26
+ createdAt: z.string().nullable(),
27
+ finishedAt: z.string().nullable(),
28
+ aiDetails: z.any().nullable(),
29
+ errorBuckets: z.array(z.any()).nullable(),
30
+ })
31
+ .passthrough();
32
+ // ---------------------------------------------------------------------------
33
+ // Comparison
34
+ // ---------------------------------------------------------------------------
35
+ export const PercyComparisonSchema = z
36
+ .object({
37
+ id: z.string(),
38
+ state: z.string().nullable(),
39
+ width: z.number().nullable(),
40
+ diffRatio: z.number().nullable(),
41
+ aiDiffRatio: z.number().nullable(),
42
+ aiProcessingState: z.string().nullable(),
43
+ aiDetails: z.any().nullable(),
44
+ appliedRegions: z.array(z.any()).nullable(),
45
+ })
46
+ .passthrough();
47
+ // ---------------------------------------------------------------------------
48
+ // Snapshot
49
+ // ---------------------------------------------------------------------------
50
+ export const PercySnapshotSchema = z
51
+ .object({
52
+ id: z.string(),
53
+ name: z.string().nullable(),
54
+ reviewState: z.string().nullable(),
55
+ reviewStateReason: z.string().nullable(),
56
+ })
57
+ .passthrough();
58
+ // ---------------------------------------------------------------------------
59
+ // Project
60
+ // ---------------------------------------------------------------------------
61
+ export const PercyProjectSchema = z
62
+ .object({
63
+ id: z.string(),
64
+ name: z.string().nullable(),
65
+ slug: z.string().nullable(),
66
+ })
67
+ .passthrough();
68
+ // ---------------------------------------------------------------------------
69
+ // Build Summary
70
+ // ---------------------------------------------------------------------------
71
+ export const PercyBuildSummarySchema = z
72
+ .object({
73
+ id: z.string(),
74
+ summary: z.string().nullable(),
75
+ })
76
+ .passthrough();
@@ -16,6 +16,8 @@ import addAppLiveTools from "./tools/applive.js";
16
16
  import addBuildInsightsTools from "./tools/build-insights.js";
17
17
  import { setupOnInitialized } from "./oninitialized.js";
18
18
  import addRCATools from "./tools/rca-agent.js";
19
+ // import addPercyMcpTools from "./tools/percy-mcp/index.js"; // v1 disabled
20
+ import addPercyMcpToolsV2 from "./tools/percy-mcp/v2/index.js";
19
21
  /**
20
22
  * Wrapper class for BrowserStack MCP Server
21
23
  * Stores a map of registered tools by name
@@ -51,6 +53,8 @@ export class BrowserStackMcpServer {
51
53
  addSelfHealTools,
52
54
  addBuildInsightsTools,
53
55
  addRCATools,
56
+ // addPercyMcpTools, // v1 — disabled, replaced by v2
57
+ addPercyMcpToolsV2,
54
58
  ];
55
59
  toolAdders.forEach((adder) => {
56
60
  // Each adder now returns a Record<string, Tool>
@@ -0,0 +1,16 @@
1
+ /**
2
+ * percy_branchline_operations — Sync, merge, or unmerge Percy branch baselines.
3
+ *
4
+ * Sync copies approved baselines to target branches.
5
+ */
6
+ import { BrowserStackConfig } from "../../../lib/types.js";
7
+ import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
8
+ interface BranchlineOperationsArgs {
9
+ action: string;
10
+ project_id?: string;
11
+ build_id?: string;
12
+ target_branch_filter?: string;
13
+ snapshot_ids?: string;
14
+ }
15
+ export declare function percyBranchlineOperations(args: BranchlineOperationsArgs, config: BrowserStackConfig): Promise<CallToolResult>;
16
+ export {};