@browserstack/mcp-server 1.2.15-beta.2 → 1.2.16-beta.1

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 (182) hide show
  1. package/dist/server-factory.js +0 -4
  2. package/dist/tools/percy-sdk.js +20 -11
  3. package/dist/tools/testmanagement-utils/get-testplan.d.ts +16 -0
  4. package/dist/tools/testmanagement-utils/get-testplan.js +99 -0
  5. package/dist/tools/testmanagement-utils/list-folders.d.ts +16 -0
  6. package/dist/tools/testmanagement-utils/list-folders.js +77 -0
  7. package/dist/tools/testmanagement-utils/list-testcases.js +1 -1
  8. package/dist/tools/testmanagement-utils/list-testplans.d.ts +15 -0
  9. package/dist/tools/testmanagement-utils/list-testplans.js +75 -0
  10. package/dist/tools/testmanagement-utils/update-testcase.d.ts +16 -0
  11. package/dist/tools/testmanagement-utils/update-testcase.js +133 -10
  12. package/dist/tools/testmanagement.d.ts +15 -0
  13. package/dist/tools/testmanagement.js +73 -2
  14. package/package.json +2 -3
  15. package/dist/lib/percy-api/auth.d.ts +0 -41
  16. package/dist/lib/percy-api/auth.js +0 -96
  17. package/dist/lib/percy-api/cache.d.ts +0 -28
  18. package/dist/lib/percy-api/cache.js +0 -48
  19. package/dist/lib/percy-api/client.d.ts +0 -69
  20. package/dist/lib/percy-api/client.js +0 -275
  21. package/dist/lib/percy-api/errors.d.ts +0 -15
  22. package/dist/lib/percy-api/errors.js +0 -52
  23. package/dist/lib/percy-api/formatter.d.ts +0 -16
  24. package/dist/lib/percy-api/formatter.js +0 -344
  25. package/dist/lib/percy-api/percy-auth.d.ts +0 -43
  26. package/dist/lib/percy-api/percy-auth.js +0 -137
  27. package/dist/lib/percy-api/percy-error-handler.d.ts +0 -24
  28. package/dist/lib/percy-api/percy-error-handler.js +0 -302
  29. package/dist/lib/percy-api/percy-session.d.ts +0 -42
  30. package/dist/lib/percy-api/percy-session.js +0 -87
  31. package/dist/lib/percy-api/polling.d.ts +0 -26
  32. package/dist/lib/percy-api/polling.js +0 -42
  33. package/dist/lib/percy-api/types.d.ts +0 -56
  34. package/dist/lib/percy-api/types.js +0 -76
  35. package/dist/tools/percy-mcp/advanced/branchline-operations.d.ts +0 -16
  36. package/dist/tools/percy-mcp/advanced/branchline-operations.js +0 -81
  37. package/dist/tools/percy-mcp/advanced/manage-variants.d.ts +0 -16
  38. package/dist/tools/percy-mcp/advanced/manage-variants.js +0 -155
  39. package/dist/tools/percy-mcp/advanced/manage-visual-monitoring.d.ts +0 -16
  40. package/dist/tools/percy-mcp/advanced/manage-visual-monitoring.js +0 -171
  41. package/dist/tools/percy-mcp/auth/auth-status.d.ts +0 -3
  42. package/dist/tools/percy-mcp/auth/auth-status.js +0 -131
  43. package/dist/tools/percy-mcp/core/approve-build.d.ts +0 -14
  44. package/dist/tools/percy-mcp/core/approve-build.js +0 -97
  45. package/dist/tools/percy-mcp/core/get-build-items.d.ts +0 -13
  46. package/dist/tools/percy-mcp/core/get-build-items.js +0 -65
  47. package/dist/tools/percy-mcp/core/get-build.d.ts +0 -10
  48. package/dist/tools/percy-mcp/core/get-build.js +0 -16
  49. package/dist/tools/percy-mcp/core/get-comparison.d.ts +0 -11
  50. package/dist/tools/percy-mcp/core/get-comparison.js +0 -59
  51. package/dist/tools/percy-mcp/core/get-snapshot.d.ts +0 -10
  52. package/dist/tools/percy-mcp/core/get-snapshot.js +0 -40
  53. package/dist/tools/percy-mcp/core/list-builds.d.ts +0 -14
  54. package/dist/tools/percy-mcp/core/list-builds.js +0 -45
  55. package/dist/tools/percy-mcp/core/list-projects.d.ts +0 -12
  56. package/dist/tools/percy-mcp/core/list-projects.js +0 -51
  57. package/dist/tools/percy-mcp/creation/create-app-snapshot.d.ts +0 -12
  58. package/dist/tools/percy-mcp/creation/create-app-snapshot.js +0 -29
  59. package/dist/tools/percy-mcp/creation/create-build.d.ts +0 -19
  60. package/dist/tools/percy-mcp/creation/create-build.js +0 -68
  61. package/dist/tools/percy-mcp/creation/create-comparison.d.ts +0 -18
  62. package/dist/tools/percy-mcp/creation/create-comparison.js +0 -90
  63. package/dist/tools/percy-mcp/creation/create-snapshot.d.ts +0 -17
  64. package/dist/tools/percy-mcp/creation/create-snapshot.js +0 -99
  65. package/dist/tools/percy-mcp/creation/finalize-build.d.ts +0 -12
  66. package/dist/tools/percy-mcp/creation/finalize-build.js +0 -33
  67. package/dist/tools/percy-mcp/creation/finalize-comparison.d.ts +0 -10
  68. package/dist/tools/percy-mcp/creation/finalize-comparison.js +0 -16
  69. package/dist/tools/percy-mcp/creation/finalize-snapshot.d.ts +0 -12
  70. package/dist/tools/percy-mcp/creation/finalize-snapshot.js +0 -33
  71. package/dist/tools/percy-mcp/creation/upload-resource.d.ts +0 -15
  72. package/dist/tools/percy-mcp/creation/upload-resource.js +0 -43
  73. package/dist/tools/percy-mcp/creation/upload-tile.d.ts +0 -11
  74. package/dist/tools/percy-mcp/creation/upload-tile.js +0 -53
  75. package/dist/tools/percy-mcp/diagnostics/analyze-logs-realtime.d.ts +0 -13
  76. package/dist/tools/percy-mcp/diagnostics/analyze-logs-realtime.js +0 -65
  77. package/dist/tools/percy-mcp/diagnostics/get-build-logs.d.ts +0 -17
  78. package/dist/tools/percy-mcp/diagnostics/get-build-logs.js +0 -74
  79. package/dist/tools/percy-mcp/diagnostics/get-network-logs.d.ts +0 -5
  80. package/dist/tools/percy-mcp/diagnostics/get-network-logs.js +0 -21
  81. package/dist/tools/percy-mcp/diagnostics/get-suggestions.d.ts +0 -7
  82. package/dist/tools/percy-mcp/diagnostics/get-suggestions.js +0 -24
  83. package/dist/tools/percy-mcp/index.d.ts +0 -36
  84. package/dist/tools/percy-mcp/index.js +0 -1137
  85. package/dist/tools/percy-mcp/intelligence/get-ai-analysis.d.ts +0 -15
  86. package/dist/tools/percy-mcp/intelligence/get-ai-analysis.js +0 -166
  87. package/dist/tools/percy-mcp/intelligence/get-ai-quota.d.ts +0 -9
  88. package/dist/tools/percy-mcp/intelligence/get-ai-quota.js +0 -73
  89. package/dist/tools/percy-mcp/intelligence/get-build-summary.d.ts +0 -11
  90. package/dist/tools/percy-mcp/intelligence/get-build-summary.js +0 -78
  91. package/dist/tools/percy-mcp/intelligence/get-rca.d.ts +0 -6
  92. package/dist/tools/percy-mcp/intelligence/get-rca.js +0 -153
  93. package/dist/tools/percy-mcp/intelligence/suggest-prompt.d.ts +0 -15
  94. package/dist/tools/percy-mcp/intelligence/suggest-prompt.js +0 -86
  95. package/dist/tools/percy-mcp/intelligence/trigger-ai-recompute.d.ts +0 -16
  96. package/dist/tools/percy-mcp/intelligence/trigger-ai-recompute.js +0 -64
  97. package/dist/tools/percy-mcp/management/create-project.d.ts +0 -14
  98. package/dist/tools/percy-mcp/management/create-project.js +0 -52
  99. package/dist/tools/percy-mcp/management/get-usage-stats.d.ts +0 -12
  100. package/dist/tools/percy-mcp/management/get-usage-stats.js +0 -61
  101. package/dist/tools/percy-mcp/management/manage-browser-targets.d.ts +0 -12
  102. package/dist/tools/percy-mcp/management/manage-browser-targets.js +0 -136
  103. package/dist/tools/percy-mcp/management/manage-comments.d.ts +0 -14
  104. package/dist/tools/percy-mcp/management/manage-comments.js +0 -147
  105. package/dist/tools/percy-mcp/management/manage-ignored-regions.d.ts +0 -18
  106. package/dist/tools/percy-mcp/management/manage-ignored-regions.js +0 -182
  107. package/dist/tools/percy-mcp/management/manage-project-settings.d.ts +0 -16
  108. package/dist/tools/percy-mcp/management/manage-project-settings.js +0 -97
  109. package/dist/tools/percy-mcp/management/manage-tokens.d.ts +0 -14
  110. package/dist/tools/percy-mcp/management/manage-tokens.js +0 -90
  111. package/dist/tools/percy-mcp/management/manage-webhooks.d.ts +0 -15
  112. package/dist/tools/percy-mcp/management/manage-webhooks.js +0 -180
  113. package/dist/tools/percy-mcp/v2/auth-status.d.ts +0 -3
  114. package/dist/tools/percy-mcp/v2/auth-status.js +0 -80
  115. package/dist/tools/percy-mcp/v2/clone-build.d.ts +0 -24
  116. package/dist/tools/percy-mcp/v2/clone-build.js +0 -539
  117. package/dist/tools/percy-mcp/v2/create-app-build.d.ts +0 -28
  118. package/dist/tools/percy-mcp/v2/create-app-build.js +0 -442
  119. package/dist/tools/percy-mcp/v2/create-build.d.ts +0 -16
  120. package/dist/tools/percy-mcp/v2/create-build.js +0 -601
  121. package/dist/tools/percy-mcp/v2/create-project.d.ts +0 -8
  122. package/dist/tools/percy-mcp/v2/create-project.js +0 -33
  123. package/dist/tools/percy-mcp/v2/discover-urls.d.ts +0 -7
  124. package/dist/tools/percy-mcp/v2/discover-urls.js +0 -38
  125. package/dist/tools/percy-mcp/v2/figma-baseline.d.ts +0 -7
  126. package/dist/tools/percy-mcp/v2/figma-baseline.js +0 -18
  127. package/dist/tools/percy-mcp/v2/figma-build.d.ts +0 -7
  128. package/dist/tools/percy-mcp/v2/figma-build.js +0 -39
  129. package/dist/tools/percy-mcp/v2/figma-link.d.ts +0 -6
  130. package/dist/tools/percy-mcp/v2/figma-link.js +0 -27
  131. package/dist/tools/percy-mcp/v2/get-ai-summary.d.ts +0 -5
  132. package/dist/tools/percy-mcp/v2/get-ai-summary.js +0 -109
  133. package/dist/tools/percy-mcp/v2/get-build-detail.d.ts +0 -22
  134. package/dist/tools/percy-mcp/v2/get-build-detail.js +0 -567
  135. package/dist/tools/percy-mcp/v2/get-builds.d.ts +0 -8
  136. package/dist/tools/percy-mcp/v2/get-builds.js +0 -63
  137. package/dist/tools/percy-mcp/v2/get-comparison.d.ts +0 -5
  138. package/dist/tools/percy-mcp/v2/get-comparison.js +0 -94
  139. package/dist/tools/percy-mcp/v2/get-devices.d.ts +0 -5
  140. package/dist/tools/percy-mcp/v2/get-devices.js +0 -33
  141. package/dist/tools/percy-mcp/v2/get-insights.d.ts +0 -7
  142. package/dist/tools/percy-mcp/v2/get-insights.js +0 -52
  143. package/dist/tools/percy-mcp/v2/get-projects.d.ts +0 -6
  144. package/dist/tools/percy-mcp/v2/get-projects.js +0 -41
  145. package/dist/tools/percy-mcp/v2/get-snapshot.d.ts +0 -5
  146. package/dist/tools/percy-mcp/v2/get-snapshot.js +0 -96
  147. package/dist/tools/percy-mcp/v2/get-test-case-history.d.ts +0 -5
  148. package/dist/tools/percy-mcp/v2/get-test-case-history.js +0 -20
  149. package/dist/tools/percy-mcp/v2/get-test-cases.d.ts +0 -6
  150. package/dist/tools/percy-mcp/v2/get-test-cases.js +0 -36
  151. package/dist/tools/percy-mcp/v2/index.d.ts +0 -35
  152. package/dist/tools/percy-mcp/v2/index.js +0 -544
  153. package/dist/tools/percy-mcp/v2/list-integrations.d.ts +0 -5
  154. package/dist/tools/percy-mcp/v2/list-integrations.js +0 -41
  155. package/dist/tools/percy-mcp/v2/manage-domains.d.ts +0 -8
  156. package/dist/tools/percy-mcp/v2/manage-domains.js +0 -33
  157. package/dist/tools/percy-mcp/v2/manage-insights-email.d.ts +0 -8
  158. package/dist/tools/percy-mcp/v2/manage-insights-email.js +0 -49
  159. package/dist/tools/percy-mcp/v2/manage-usage-alerts.d.ts +0 -10
  160. package/dist/tools/percy-mcp/v2/manage-usage-alerts.js +0 -43
  161. package/dist/tools/percy-mcp/v2/migrate-integrations.d.ts +0 -6
  162. package/dist/tools/percy-mcp/v2/migrate-integrations.js +0 -20
  163. package/dist/tools/percy-mcp/v2/preview-comparison.d.ts +0 -5
  164. package/dist/tools/percy-mcp/v2/preview-comparison.js +0 -17
  165. package/dist/tools/percy-mcp/v2/search-build-items.d.ts +0 -12
  166. package/dist/tools/percy-mcp/v2/search-build-items.js +0 -45
  167. package/dist/tools/percy-mcp/workflows/auto-triage.d.ts +0 -7
  168. package/dist/tools/percy-mcp/workflows/auto-triage.js +0 -82
  169. package/dist/tools/percy-mcp/workflows/clone-build.d.ts +0 -22
  170. package/dist/tools/percy-mcp/workflows/clone-build.js +0 -414
  171. package/dist/tools/percy-mcp/workflows/create-percy-build.d.ts +0 -32
  172. package/dist/tools/percy-mcp/workflows/create-percy-build.js +0 -434
  173. package/dist/tools/percy-mcp/workflows/debug-failed-build.d.ts +0 -5
  174. package/dist/tools/percy-mcp/workflows/debug-failed-build.js +0 -122
  175. package/dist/tools/percy-mcp/workflows/diff-explain.d.ts +0 -6
  176. package/dist/tools/percy-mcp/workflows/diff-explain.js +0 -147
  177. package/dist/tools/percy-mcp/workflows/pr-visual-report.d.ts +0 -8
  178. package/dist/tools/percy-mcp/workflows/pr-visual-report.js +0 -184
  179. package/dist/tools/percy-mcp/workflows/run-tests.d.ts +0 -17
  180. package/dist/tools/percy-mcp/workflows/run-tests.js +0 -107
  181. package/dist/tools/percy-mcp/workflows/snapshot-urls.d.ts +0 -18
  182. package/dist/tools/percy-mcp/workflows/snapshot-urls.js +0 -197
@@ -1,1137 +0,0 @@
1
- /**
2
- * Percy MCP tools — CRUD-organized tools for Percy visual testing.
3
- *
4
- * Registers 41 tools organized by CRUD action:
5
- *
6
- * === CREATE (6) ===
7
- * percy_create_project, percy_create_percy_build, percy_create_build,
8
- * percy_create_snapshot, percy_create_app_snapshot, percy_create_comparison
9
- *
10
- * === READ (17) ===
11
- * percy_list_projects, percy_list_builds, percy_get_build,
12
- * percy_get_build_items, percy_get_snapshot, percy_get_comparison,
13
- * percy_get_ai_analysis, percy_get_build_summary, percy_get_ai_quota,
14
- * percy_get_rca, percy_get_suggestions, percy_get_network_logs,
15
- * percy_get_build_logs, percy_get_usage_stats, percy_auth_status
16
- *
17
- * === UPDATE (12) ===
18
- * percy_approve_build, percy_manage_project_settings,
19
- * percy_manage_browser_targets, percy_manage_tokens,
20
- * percy_manage_webhooks, percy_manage_ignored_regions,
21
- * percy_manage_comments, percy_manage_variants,
22
- * percy_manage_visual_monitoring, percy_trigger_ai_recompute,
23
- * percy_suggest_prompt, percy_branchline_operations
24
- *
25
- * === FINALIZE / UPLOAD (6) ===
26
- * percy_finalize_build, percy_finalize_snapshot, percy_finalize_comparison,
27
- * percy_upload_resource, percy_upload_tile, percy_analyze_logs_realtime
28
- *
29
- * === WORKFLOWS (4) ===
30
- * percy_pr_visual_report, percy_auto_triage,
31
- * percy_debug_failed_build, percy_diff_explain
32
- */
33
- import { handleMCPError } from "../../lib/utils.js";
34
- import { trackMCP } from "../../index.js";
35
- import { z } from "zod";
36
- import { percyListProjects } from "./core/list-projects.js";
37
- import { percyListBuilds } from "./core/list-builds.js";
38
- import { percyGetBuild } from "./core/get-build.js";
39
- import { percyGetBuildItems } from "./core/get-build-items.js";
40
- import { percyGetSnapshot } from "./core/get-snapshot.js";
41
- import { percyGetComparison } from "./core/get-comparison.js";
42
- import { percyCreateBuild } from "./creation/create-build.js";
43
- import { percyCreateSnapshot } from "./creation/create-snapshot.js";
44
- import { percyUploadResource } from "./creation/upload-resource.js";
45
- import { percyFinalizeSnapshot } from "./creation/finalize-snapshot.js";
46
- import { percyFinalizeBuild } from "./creation/finalize-build.js";
47
- import { percyCreateAppSnapshot } from "./creation/create-app-snapshot.js";
48
- import { percyCreateComparison } from "./creation/create-comparison.js";
49
- import { percyUploadTile } from "./creation/upload-tile.js";
50
- import { percyFinalizeComparison } from "./creation/finalize-comparison.js";
51
- import { percyApproveBuild } from "./core/approve-build.js";
52
- import { percyGetAiAnalysis } from "./intelligence/get-ai-analysis.js";
53
- import { percyGetBuildSummary } from "./intelligence/get-build-summary.js";
54
- import { percyGetAiQuota } from "./intelligence/get-ai-quota.js";
55
- import { percyGetRca } from "./intelligence/get-rca.js";
56
- import { percyTriggerAiRecompute } from "./intelligence/trigger-ai-recompute.js";
57
- import { percySuggestPrompt } from "./intelligence/suggest-prompt.js";
58
- import { percyGetSuggestions } from "./diagnostics/get-suggestions.js";
59
- import { percyGetNetworkLogs } from "./diagnostics/get-network-logs.js";
60
- import { percyGetBuildLogs } from "./diagnostics/get-build-logs.js";
61
- import { percyAnalyzeLogsRealtime } from "./diagnostics/analyze-logs-realtime.js";
62
- import { percyPrVisualReport } from "./workflows/pr-visual-report.js";
63
- import { percyCreatePercyBuild } from "./workflows/create-percy-build.js";
64
- import { percyCloneBuild } from "./workflows/clone-build.js";
65
- import { percyAutoTriage } from "./workflows/auto-triage.js";
66
- import { percyDebugFailedBuild } from "./workflows/debug-failed-build.js";
67
- import { percyDiffExplain } from "./workflows/diff-explain.js";
68
- import { percySnapshotUrls } from "./workflows/snapshot-urls.js";
69
- import { percyRunTests } from "./workflows/run-tests.js";
70
- import { percyAuthStatus } from "./auth/auth-status.js";
71
- import { percyCreateProject } from "./management/create-project.js";
72
- import { percyManageProjectSettings } from "./management/manage-project-settings.js";
73
- import { percyManageBrowserTargets } from "./management/manage-browser-targets.js";
74
- import { percyManageTokens } from "./management/manage-tokens.js";
75
- import { percyManageWebhooks } from "./management/manage-webhooks.js";
76
- import { percyManageIgnoredRegions } from "./management/manage-ignored-regions.js";
77
- import { percyManageComments } from "./management/manage-comments.js";
78
- import { percyGetUsageStats } from "./management/get-usage-stats.js";
79
- import { percyManageVisualMonitoring } from "./advanced/manage-visual-monitoring.js";
80
- import { percyBranchlineOperations } from "./advanced/branchline-operations.js";
81
- import { percyManageVariants } from "./advanced/manage-variants.js";
82
- export function registerPercyMcpTools(server, config) {
83
- const tools = {};
84
- // =========================================================================
85
- // === CREATE ===
86
- // =========================================================================
87
- // -------------------------------------------------------------------------
88
- // percy_create_project
89
- // -------------------------------------------------------------------------
90
- tools.percy_create_project = server.tool("percy_create_project", "Create a new Percy project. Auto-creates if doesn't exist, returns project token.", {
91
- name: z.string().describe("Project name (e.g. 'my-web-app')"),
92
- type: z
93
- .enum(["web", "automate"])
94
- .optional()
95
- .describe("Project type: 'web' for Percy Web, 'automate' for Percy Automate (default: auto-detect)"),
96
- }, async (args) => {
97
- try {
98
- trackMCP("percy_create_project", server.server.getClientVersion(), config);
99
- return await percyCreateProject(args, config);
100
- }
101
- catch (error) {
102
- return handleMCPError("percy_create_project", server, config, error);
103
- }
104
- });
105
- // -------------------------------------------------------------------------
106
- // percy_create_percy_build
107
- // -------------------------------------------------------------------------
108
- tools.percy_create_percy_build = server.tool("percy_create_percy_build", "Create a complete Percy build with snapshots. Supports URL scanning, screenshot upload, test wrapping, or build cloning. The primary build creation tool.", {
109
- project_name: z
110
- .string()
111
- .describe("Percy project name (auto-creates if doesn't exist)"),
112
- urls: z
113
- .string()
114
- .optional()
115
- .describe("Comma-separated URLs to snapshot, e.g. 'http://localhost:3000,http://localhost:3000/about'"),
116
- screenshots_dir: z
117
- .string()
118
- .optional()
119
- .describe("Directory path containing PNG/JPG screenshots to upload"),
120
- screenshot_files: z
121
- .string()
122
- .optional()
123
- .describe("Comma-separated file paths to PNG/JPG screenshots"),
124
- test_command: z
125
- .string()
126
- .optional()
127
- .describe("Test command to wrap with Percy, e.g. 'npx cypress run' or 'npm test'"),
128
- clone_build_id: z
129
- .string()
130
- .optional()
131
- .describe("Build ID to clone snapshots from"),
132
- branch: z
133
- .string()
134
- .optional()
135
- .describe("Git branch (auto-detected from git if not provided)"),
136
- commit_sha: z
137
- .string()
138
- .optional()
139
- .describe("Git commit SHA (auto-detected from git if not provided)"),
140
- widths: z
141
- .string()
142
- .optional()
143
- .describe("Comma-separated viewport widths, e.g. '375,768,1280' (default: 375,1280)"),
144
- snapshot_names: z
145
- .string()
146
- .optional()
147
- .describe("Comma-separated snapshot names (for screenshots — defaults to filename)"),
148
- test_case: z
149
- .string()
150
- .optional()
151
- .describe("Test case name to associate snapshots with"),
152
- type: z
153
- .enum(["web", "app", "automate"])
154
- .optional()
155
- .describe("Project type (default: web)"),
156
- }, async (args) => {
157
- try {
158
- trackMCP("percy_create_percy_build", server.server.getClientVersion(), config);
159
- return await percyCreatePercyBuild(args, config);
160
- }
161
- catch (error) {
162
- return handleMCPError("percy_create_percy_build", server, config, error);
163
- }
164
- });
165
- // -------------------------------------------------------------------------
166
- // percy_create_build
167
- // -------------------------------------------------------------------------
168
- tools.percy_create_build = server.tool("percy_create_build", "Create an empty Percy build (low-level). Use percy_create_percy_build for full automation.", {
169
- project_id: z
170
- .string()
171
- .optional()
172
- .describe("Percy project ID (optional if PERCY_TOKEN is project-scoped)"),
173
- branch: z.string().describe("Git branch name"),
174
- commit_sha: z.string().describe("Git commit SHA"),
175
- commit_message: z.string().optional().describe("Git commit message"),
176
- pull_request_number: z
177
- .string()
178
- .optional()
179
- .describe("Pull request number"),
180
- type: z
181
- .string()
182
- .optional()
183
- .describe("Project type: web, app, automate, generic"),
184
- }, async (args) => {
185
- try {
186
- trackMCP("percy_create_build", server.server.getClientVersion(), config);
187
- return await percyCreateBuild(args, config);
188
- }
189
- catch (error) {
190
- return handleMCPError("percy_create_build", server, config, error);
191
- }
192
- });
193
- // -------------------------------------------------------------------------
194
- // percy_create_snapshot
195
- // -------------------------------------------------------------------------
196
- tools.percy_create_snapshot = server.tool("percy_create_snapshot", "Create a snapshot in a Percy build with DOM resources (low-level web flow).", {
197
- build_id: z.string().describe("Percy build ID"),
198
- name: z.string().describe("Snapshot name"),
199
- widths: z
200
- .string()
201
- .optional()
202
- .describe("Comma-separated viewport widths, e.g. '375,768,1280'"),
203
- enable_javascript: z.boolean().optional(),
204
- resources: z
205
- .string()
206
- .optional()
207
- .describe('JSON array of resources: [{"id":"sha","resource-url":"url","is-root":true}]'),
208
- }, async (args) => {
209
- try {
210
- trackMCP("percy_create_snapshot", server.server.getClientVersion(), config);
211
- return await percyCreateSnapshot(args, config);
212
- }
213
- catch (error) {
214
- return handleMCPError("percy_create_snapshot", server, config, error);
215
- }
216
- });
217
- // -------------------------------------------------------------------------
218
- // percy_create_app_snapshot
219
- // -------------------------------------------------------------------------
220
- tools.percy_create_app_snapshot = server.tool("percy_create_app_snapshot", "Create a snapshot for App Percy / screenshot builds (low-level app flow).", {
221
- build_id: z.string().describe("Percy build ID"),
222
- name: z.string().describe("Snapshot name"),
223
- test_case: z.string().optional().describe("Test case name"),
224
- }, async (args) => {
225
- try {
226
- trackMCP("percy_create_app_snapshot", server.server.getClientVersion(), config);
227
- return await percyCreateAppSnapshot(args, config);
228
- }
229
- catch (error) {
230
- return handleMCPError("percy_create_app_snapshot", server, config, error);
231
- }
232
- });
233
- // -------------------------------------------------------------------------
234
- // percy_create_comparison
235
- // -------------------------------------------------------------------------
236
- tools.percy_create_comparison = server.tool("percy_create_comparison", "Create a comparison with device tag and tiles for screenshot builds (low-level).", {
237
- snapshot_id: z.string().describe("Percy snapshot ID"),
238
- tag_name: z.string().describe("Device/browser name, e.g. 'iPhone 13'"),
239
- tag_width: z.number().describe("Tag width in pixels"),
240
- tag_height: z.number().describe("Tag height in pixels"),
241
- tag_os_name: z.string().optional().describe("OS name, e.g. 'iOS'"),
242
- tag_os_version: z.string().optional().describe("OS version, e.g. '16.0'"),
243
- tag_browser_name: z
244
- .string()
245
- .optional()
246
- .describe("Browser name, e.g. 'Safari'"),
247
- tag_orientation: z.string().optional().describe("portrait or landscape"),
248
- tiles: z
249
- .string()
250
- .describe("JSON array of tiles: [{sha, status-bar-height?, nav-bar-height?}]"),
251
- }, async (args) => {
252
- try {
253
- trackMCP("percy_create_comparison", server.server.getClientVersion(), config);
254
- return await percyCreateComparison(args, config);
255
- }
256
- catch (error) {
257
- return handleMCPError("percy_create_comparison", server, config, error);
258
- }
259
- });
260
- // -------------------------------------------------------------------------
261
- // percy_clone_build — Cross-project build cloning
262
- // -------------------------------------------------------------------------
263
- tools.percy_clone_build = server.tool("percy_clone_build", "Clone snapshots from one Percy build to another project. Downloads screenshots from source and re-uploads to target. Works across different projects and orgs. Handles the entire flow: read source → create target build → clone each snapshot with comparisons → finalize.", {
264
- source_build_id: z
265
- .string()
266
- .describe("Build ID to clone FROM (the source)"),
267
- target_project_name: z
268
- .string()
269
- .describe("Project name to clone INTO. Use the EXACT project name from Percy dashboard. If project doesn't exist, a new one is created."),
270
- target_token: z
271
- .string()
272
- .optional()
273
- .describe("Percy token for the TARGET project. Use this to clone into an existing project without creating a new one. Get it from project settings."),
274
- source_token: z
275
- .string()
276
- .optional()
277
- .describe("Percy token for reading the source build (if different from PERCY_TOKEN). Must be a full-access web_* or auto_* token."),
278
- branch: z
279
- .string()
280
- .optional()
281
- .describe("Branch for the new build (auto-detected from git)"),
282
- commit_sha: z
283
- .string()
284
- .optional()
285
- .describe("Commit SHA for the new build (auto-detected from git)"),
286
- }, async (args) => {
287
- try {
288
- trackMCP("percy_clone_build", server.server.getClientVersion(), config);
289
- return await percyCloneBuild(args, config);
290
- }
291
- catch (error) {
292
- return handleMCPError("percy_clone_build", server, config, error);
293
- }
294
- });
295
- // =========================================================================
296
- // === READ ===
297
- // =========================================================================
298
- // -------------------------------------------------------------------------
299
- // percy_list_projects
300
- // -------------------------------------------------------------------------
301
- tools.percy_list_projects = server.tool("percy_list_projects", "List all Percy projects in your organization.", {
302
- org_id: z
303
- .string()
304
- .optional()
305
- .describe("Percy organization ID. If not provided, uses token scope."),
306
- search: z
307
- .string()
308
- .optional()
309
- .describe("Filter projects by name (substring match)"),
310
- limit: z.number().optional().describe("Max results (default 10, max 50)"),
311
- }, async (args) => {
312
- try {
313
- trackMCP("percy_list_projects", server.server.getClientVersion(), config);
314
- return await percyListProjects(args, config);
315
- }
316
- catch (error) {
317
- return handleMCPError("percy_list_projects", server, config, error);
318
- }
319
- });
320
- // -------------------------------------------------------------------------
321
- // percy_list_builds
322
- // -------------------------------------------------------------------------
323
- tools.percy_list_builds = server.tool("percy_list_builds", "List Percy builds with filters (branch, state, SHA, tags).", {
324
- project_id: z
325
- .string()
326
- .optional()
327
- .describe("Percy project ID. If not provided, uses PERCY_TOKEN scope."),
328
- branch: z.string().optional().describe("Filter by branch name"),
329
- state: z
330
- .string()
331
- .optional()
332
- .describe("Filter by state: pending, processing, finished, failed"),
333
- sha: z.string().optional().describe("Filter by commit SHA"),
334
- limit: z.number().optional().describe("Max results (default 10, max 30)"),
335
- }, async (args) => {
336
- try {
337
- trackMCP("percy_list_builds", server.server.getClientVersion(), config);
338
- return await percyListBuilds(args, config);
339
- }
340
- catch (error) {
341
- return handleMCPError("percy_list_builds", server, config, error);
342
- }
343
- });
344
- // -------------------------------------------------------------------------
345
- // percy_get_build
346
- // -------------------------------------------------------------------------
347
- tools.percy_get_build = server.tool("percy_get_build", "Get full Percy build details: state, snapshots, AI metrics, summary.", {
348
- build_id: z.string().describe("Percy build ID"),
349
- }, async (args) => {
350
- try {
351
- trackMCP("percy_get_build", server.server.getClientVersion(), config);
352
- return await percyGetBuild(args, config);
353
- }
354
- catch (error) {
355
- return handleMCPError("percy_get_build", server, config, error);
356
- }
357
- });
358
- // -------------------------------------------------------------------------
359
- // percy_get_build_items
360
- // -------------------------------------------------------------------------
361
- tools.percy_get_build_items = server.tool("percy_get_build_items", "List snapshots in a build by category: changed, new, removed, unchanged, failed.", {
362
- build_id: z.string().describe("Percy build ID"),
363
- category: z
364
- .string()
365
- .optional()
366
- .describe("Filter category: changed, new, removed, unchanged, failed"),
367
- sort_by: z
368
- .string()
369
- .optional()
370
- .describe("Sort field (e.g. diff-ratio, name)"),
371
- limit: z
372
- .number()
373
- .optional()
374
- .describe("Max results (default 20, max 100)"),
375
- }, async (args) => {
376
- try {
377
- trackMCP("percy_get_build_items", server.server.getClientVersion(), config);
378
- return await percyGetBuildItems(args, config);
379
- }
380
- catch (error) {
381
- return handleMCPError("percy_get_build_items", server, config, error);
382
- }
383
- });
384
- // -------------------------------------------------------------------------
385
- // percy_get_snapshot
386
- // -------------------------------------------------------------------------
387
- tools.percy_get_snapshot = server.tool("percy_get_snapshot", "Get snapshot with all comparisons, screenshots, and diff data.", {
388
- snapshot_id: z.string().describe("Percy snapshot ID"),
389
- }, async (args) => {
390
- try {
391
- trackMCP("percy_get_snapshot", server.server.getClientVersion(), config);
392
- return await percyGetSnapshot(args, config);
393
- }
394
- catch (error) {
395
- return handleMCPError("percy_get_snapshot", server, config, error);
396
- }
397
- });
398
- // -------------------------------------------------------------------------
399
- // percy_get_comparison
400
- // -------------------------------------------------------------------------
401
- tools.percy_get_comparison = server.tool("percy_get_comparison", "Get comparison details: diff ratio, AI analysis, screenshot URLs.", {
402
- comparison_id: z.string().describe("Percy comparison ID"),
403
- include_images: z
404
- .boolean()
405
- .optional()
406
- .describe("Include screenshot image URLs in response (default false)"),
407
- }, async (args) => {
408
- try {
409
- trackMCP("percy_get_comparison", server.server.getClientVersion(), config);
410
- return await percyGetComparison(args, config);
411
- }
412
- catch (error) {
413
- return handleMCPError("percy_get_comparison", server, config, error);
414
- }
415
- });
416
- // -------------------------------------------------------------------------
417
- // percy_get_ai_analysis
418
- // -------------------------------------------------------------------------
419
- tools.percy_get_ai_analysis = server.tool("percy_get_ai_analysis", "Get AI visual diff analysis: change types, bug classifications, diff reduction.", {
420
- comparison_id: z
421
- .string()
422
- .optional()
423
- .describe("Get AI analysis for a single comparison"),
424
- build_id: z
425
- .string()
426
- .optional()
427
- .describe("Get aggregated AI analysis for an entire build"),
428
- }, async (args) => {
429
- try {
430
- trackMCP("percy_get_ai_analysis", server.server.getClientVersion(), config);
431
- return await percyGetAiAnalysis(args, config);
432
- }
433
- catch (error) {
434
- return handleMCPError("percy_get_ai_analysis", server, config, error);
435
- }
436
- });
437
- // -------------------------------------------------------------------------
438
- // percy_get_build_summary
439
- // -------------------------------------------------------------------------
440
- tools.percy_get_build_summary = server.tool("percy_get_build_summary", "Get AI-generated natural language summary of all visual changes.", {
441
- build_id: z.string().describe("Percy build ID"),
442
- }, async (args) => {
443
- try {
444
- trackMCP("percy_get_build_summary", server.server.getClientVersion(), config);
445
- return await percyGetBuildSummary(args, config);
446
- }
447
- catch (error) {
448
- return handleMCPError("percy_get_build_summary", server, config, error);
449
- }
450
- });
451
- // -------------------------------------------------------------------------
452
- // percy_get_ai_quota
453
- // -------------------------------------------------------------------------
454
- tools.percy_get_ai_quota = server.tool("percy_get_ai_quota", "Check AI regeneration quota: daily usage and limits.", {}, async () => {
455
- try {
456
- trackMCP("percy_get_ai_quota", server.server.getClientVersion(), config);
457
- return await percyGetAiQuota({}, config);
458
- }
459
- catch (error) {
460
- return handleMCPError("percy_get_ai_quota", server, config, error);
461
- }
462
- });
463
- // -------------------------------------------------------------------------
464
- // percy_get_rca
465
- // -------------------------------------------------------------------------
466
- tools.percy_get_rca = server.tool("percy_get_rca", "Get Root Cause Analysis: maps visual diffs to DOM/CSS changes.", {
467
- comparison_id: z.string().describe("Percy comparison ID"),
468
- trigger_if_missing: z
469
- .boolean()
470
- .optional()
471
- .describe("Auto-trigger RCA if not yet run (default true)"),
472
- }, async (args) => {
473
- try {
474
- trackMCP("percy_get_rca", server.server.getClientVersion(), config);
475
- return await percyGetRca(args, config);
476
- }
477
- catch (error) {
478
- return handleMCPError("percy_get_rca", server, config, error);
479
- }
480
- });
481
- // -------------------------------------------------------------------------
482
- // percy_get_suggestions
483
- // -------------------------------------------------------------------------
484
- tools.percy_get_suggestions = server.tool("percy_get_suggestions", "Get build failure diagnostics: categorized issues with fix steps.", {
485
- build_id: z.string().describe("Percy build ID"),
486
- reference_type: z
487
- .string()
488
- .optional()
489
- .describe("Filter: build, snapshot, or comparison"),
490
- reference_id: z
491
- .string()
492
- .optional()
493
- .describe("Specific snapshot or comparison ID"),
494
- }, async (args) => {
495
- try {
496
- trackMCP("percy_get_suggestions", server.server.getClientVersion(), config);
497
- return await percyGetSuggestions(args, config);
498
- }
499
- catch (error) {
500
- return handleMCPError("percy_get_suggestions", server, config, error);
501
- }
502
- });
503
- // -------------------------------------------------------------------------
504
- // percy_get_network_logs
505
- // -------------------------------------------------------------------------
506
- tools.percy_get_network_logs = server.tool("percy_get_network_logs", "Get network request logs: per-URL status comparison (base vs head).", {
507
- comparison_id: z.string().describe("Percy comparison ID"),
508
- }, async (args) => {
509
- try {
510
- trackMCP("percy_get_network_logs", server.server.getClientVersion(), config);
511
- return await percyGetNetworkLogs(args, config);
512
- }
513
- catch (error) {
514
- return handleMCPError("percy_get_network_logs", server, config, error);
515
- }
516
- });
517
- // -------------------------------------------------------------------------
518
- // percy_get_build_logs
519
- // -------------------------------------------------------------------------
520
- tools.percy_get_build_logs = server.tool("percy_get_build_logs", "Get raw build logs (CLI, renderer, proxy) with level filtering.", {
521
- build_id: z.string().describe("Percy build ID"),
522
- service: z
523
- .string()
524
- .optional()
525
- .describe("Filter by service: cli, renderer, jackproxy"),
526
- reference_type: z
527
- .string()
528
- .optional()
529
- .describe("Reference scope: build, snapshot, comparison"),
530
- reference_id: z
531
- .string()
532
- .optional()
533
- .describe("Specific snapshot or comparison ID"),
534
- level: z
535
- .string()
536
- .optional()
537
- .describe("Filter by log level: error, warn, info, debug"),
538
- }, async (args) => {
539
- try {
540
- trackMCP("percy_get_build_logs", server.server.getClientVersion(), config);
541
- return await percyGetBuildLogs(args, config);
542
- }
543
- catch (error) {
544
- return handleMCPError("percy_get_build_logs", server, config, error);
545
- }
546
- });
547
- // -------------------------------------------------------------------------
548
- // percy_get_usage_stats
549
- // -------------------------------------------------------------------------
550
- tools.percy_get_usage_stats = server.tool("percy_get_usage_stats", "Get organization usage: screenshot counts, quotas, AI comparisons.", {
551
- org_id: z.string().describe("Percy organization ID"),
552
- product: z
553
- .string()
554
- .optional()
555
- .describe("Filter by product type (e.g., 'percy', 'app_percy')"),
556
- }, async (args) => {
557
- try {
558
- trackMCP("percy_get_usage_stats", server.server.getClientVersion(), config);
559
- return await percyGetUsageStats(args, config);
560
- }
561
- catch (error) {
562
- return handleMCPError("percy_get_usage_stats", server, config, error);
563
- }
564
- });
565
- // -------------------------------------------------------------------------
566
- // percy_auth_status
567
- // -------------------------------------------------------------------------
568
- tools.percy_auth_status = server.tool("percy_auth_status", "Check Percy auth: which tokens are set, validated, and their scope.", {}, async () => {
569
- try {
570
- trackMCP("percy_auth_status", server.server.getClientVersion(), config);
571
- return await percyAuthStatus({}, config);
572
- }
573
- catch (error) {
574
- return handleMCPError("percy_auth_status", server, config, error);
575
- }
576
- });
577
- // =========================================================================
578
- // === UPDATE ===
579
- // =========================================================================
580
- // -------------------------------------------------------------------------
581
- // percy_approve_build
582
- // -------------------------------------------------------------------------
583
- tools.percy_approve_build = server.tool("percy_approve_build", "Approve, reject, or request changes on a Percy build.", {
584
- build_id: z.string().describe("Percy build ID to review"),
585
- action: z
586
- .enum(["approve", "request_changes", "unapprove", "reject"])
587
- .describe("Review action"),
588
- snapshot_ids: z
589
- .string()
590
- .optional()
591
- .describe("Comma-separated snapshot IDs (required for request_changes)"),
592
- reason: z
593
- .string()
594
- .optional()
595
- .describe("Optional reason for the review action"),
596
- }, async (args) => {
597
- try {
598
- trackMCP("percy_approve_build", server.server.getClientVersion(), config);
599
- return await percyApproveBuild(args, config);
600
- }
601
- catch (error) {
602
- return handleMCPError("percy_approve_build", server, config, error);
603
- }
604
- });
605
- // -------------------------------------------------------------------------
606
- // percy_manage_project_settings
607
- // -------------------------------------------------------------------------
608
- tools.percy_manage_project_settings = server.tool("percy_manage_project_settings", "Update Percy project settings: diff sensitivity, auto-approve, IntelliIgnore.", {
609
- project_id: z.string().describe("Percy project ID"),
610
- settings: z
611
- .string()
612
- .optional()
613
- .describe('JSON string of attributes to update, e.g. \'{"diff-sensitivity":0.1,"auto-approve-branch-filter":"main"}\''),
614
- confirm_destructive: z
615
- .boolean()
616
- .optional()
617
- .describe("Set to true to confirm high-risk changes (auto-approve/approval-required branch filters)"),
618
- }, async (args) => {
619
- try {
620
- trackMCP("percy_manage_project_settings", server.server.getClientVersion(), config);
621
- return await percyManageProjectSettings(args, config);
622
- }
623
- catch (error) {
624
- return handleMCPError("percy_manage_project_settings", server, config, error);
625
- }
626
- });
627
- // -------------------------------------------------------------------------
628
- // percy_manage_browser_targets
629
- // -------------------------------------------------------------------------
630
- tools.percy_manage_browser_targets = server.tool("percy_manage_browser_targets", "Add or remove browser targets (Chrome, Firefox, Safari, Edge).", {
631
- project_id: z.string().describe("Percy project ID"),
632
- action: z
633
- .enum(["list", "add", "remove"])
634
- .optional()
635
- .describe("Action to perform (default: list)"),
636
- browser_family: z
637
- .string()
638
- .optional()
639
- .describe("Browser family ID to add or project-browser-target ID to remove"),
640
- }, async (args) => {
641
- try {
642
- trackMCP("percy_manage_browser_targets", server.server.getClientVersion(), config);
643
- return await percyManageBrowserTargets(args, config);
644
- }
645
- catch (error) {
646
- return handleMCPError("percy_manage_browser_targets", server, config, error);
647
- }
648
- });
649
- // -------------------------------------------------------------------------
650
- // percy_manage_tokens
651
- // -------------------------------------------------------------------------
652
- tools.percy_manage_tokens = server.tool("percy_manage_tokens", "View (masked) or rotate Percy project tokens.", {
653
- project_id: z.string().describe("Percy project ID"),
654
- action: z
655
- .enum(["list", "rotate"])
656
- .optional()
657
- .describe("Action to perform (default: list)"),
658
- role: z
659
- .string()
660
- .optional()
661
- .describe("Token role for rotation (e.g., 'write', 'read')"),
662
- }, async (args) => {
663
- try {
664
- trackMCP("percy_manage_tokens", server.server.getClientVersion(), config);
665
- return await percyManageTokens(args, config);
666
- }
667
- catch (error) {
668
- return handleMCPError("percy_manage_tokens", server, config, error);
669
- }
670
- });
671
- // -------------------------------------------------------------------------
672
- // percy_manage_webhooks
673
- // -------------------------------------------------------------------------
674
- tools.percy_manage_webhooks = server.tool("percy_manage_webhooks", "Create, update, or delete webhooks for build events.", {
675
- project_id: z.string().describe("Percy project ID"),
676
- action: z
677
- .enum(["list", "create", "update", "delete"])
678
- .optional()
679
- .describe("Action to perform (default: list)"),
680
- webhook_id: z
681
- .string()
682
- .optional()
683
- .describe("Webhook ID (required for update/delete)"),
684
- url: z.string().optional().describe("Webhook URL (required for create)"),
685
- events: z
686
- .string()
687
- .optional()
688
- .describe("Comma-separated event types, e.g. 'build:finished,build:failed'"),
689
- description: z
690
- .string()
691
- .optional()
692
- .describe("Human-readable webhook description"),
693
- }, async (args) => {
694
- try {
695
- trackMCP("percy_manage_webhooks", server.server.getClientVersion(), config);
696
- return await percyManageWebhooks(args, config);
697
- }
698
- catch (error) {
699
- return handleMCPError("percy_manage_webhooks", server, config, error);
700
- }
701
- });
702
- // -------------------------------------------------------------------------
703
- // percy_manage_ignored_regions
704
- // -------------------------------------------------------------------------
705
- tools.percy_manage_ignored_regions = server.tool("percy_manage_ignored_regions", "Create, save, or delete ignored regions on comparisons.", {
706
- comparison_id: z
707
- .string()
708
- .optional()
709
- .describe("Percy comparison ID (required for list/create)"),
710
- action: z
711
- .enum(["list", "create", "save", "delete"])
712
- .optional()
713
- .describe("Action to perform (default: list)"),
714
- region_id: z
715
- .string()
716
- .optional()
717
- .describe("Region revision ID (required for delete)"),
718
- type: z
719
- .string()
720
- .optional()
721
- .describe("Region type: raw, xpath, css, full_page"),
722
- coordinates: z
723
- .string()
724
- .optional()
725
- .describe('JSON bounding box for raw type: {"x":0,"y":0,"width":100,"height":100}'),
726
- selector: z.string().optional().describe("XPath or CSS selector string"),
727
- }, async (args) => {
728
- try {
729
- trackMCP("percy_manage_ignored_regions", server.server.getClientVersion(), config);
730
- return await percyManageIgnoredRegions(args, config);
731
- }
732
- catch (error) {
733
- return handleMCPError("percy_manage_ignored_regions", server, config, error);
734
- }
735
- });
736
- // -------------------------------------------------------------------------
737
- // percy_manage_comments
738
- // -------------------------------------------------------------------------
739
- tools.percy_manage_comments = server.tool("percy_manage_comments", "Create or close comment threads on snapshots.", {
740
- build_id: z
741
- .string()
742
- .optional()
743
- .describe("Percy build ID (required for list)"),
744
- snapshot_id: z
745
- .string()
746
- .optional()
747
- .describe("Percy snapshot ID (required for create)"),
748
- action: z
749
- .enum(["list", "create", "close"])
750
- .optional()
751
- .describe("Action to perform (default: list)"),
752
- thread_id: z
753
- .string()
754
- .optional()
755
- .describe("Comment thread ID (required for close)"),
756
- body: z
757
- .string()
758
- .optional()
759
- .describe("Comment body text (required for create)"),
760
- }, async (args) => {
761
- try {
762
- trackMCP("percy_manage_comments", server.server.getClientVersion(), config);
763
- return await percyManageComments(args, config);
764
- }
765
- catch (error) {
766
- return handleMCPError("percy_manage_comments", server, config, error);
767
- }
768
- });
769
- // -------------------------------------------------------------------------
770
- // percy_manage_variants
771
- // -------------------------------------------------------------------------
772
- tools.percy_manage_variants = server.tool("percy_manage_variants", "Create or update A/B testing variants.", {
773
- comparison_id: z
774
- .string()
775
- .optional()
776
- .describe("Percy comparison ID (required for list)"),
777
- snapshot_id: z
778
- .string()
779
- .optional()
780
- .describe("Percy snapshot ID (required for create)"),
781
- action: z
782
- .enum(["list", "create", "update"])
783
- .optional()
784
- .describe("Action to perform (default: list)"),
785
- variant_id: z
786
- .string()
787
- .optional()
788
- .describe("Variant ID (required for update)"),
789
- name: z
790
- .string()
791
- .optional()
792
- .describe("Variant name (required for create)"),
793
- state: z.string().optional().describe("Variant state (for update)"),
794
- }, async (args) => {
795
- try {
796
- trackMCP("percy_manage_variants", server.server.getClientVersion(), config);
797
- return await percyManageVariants(args, config);
798
- }
799
- catch (error) {
800
- return handleMCPError("percy_manage_variants", server, config, error);
801
- }
802
- });
803
- // -------------------------------------------------------------------------
804
- // percy_manage_visual_monitoring
805
- // -------------------------------------------------------------------------
806
- tools.percy_manage_visual_monitoring = server.tool("percy_manage_visual_monitoring", "Create or update Visual Monitoring projects.", {
807
- org_id: z
808
- .string()
809
- .optional()
810
- .describe("Percy organization ID (required for list/create)"),
811
- project_id: z
812
- .string()
813
- .optional()
814
- .describe("Visual Monitoring project ID (required for update)"),
815
- action: z
816
- .enum(["list", "create", "update"])
817
- .optional()
818
- .describe("Action to perform (default: list)"),
819
- urls: z
820
- .string()
821
- .optional()
822
- .describe("Comma-separated URLs to monitor, e.g. 'https://example.com,https://example.com/about'"),
823
- cron: z
824
- .string()
825
- .optional()
826
- .describe("Cron expression for monitoring schedule, e.g. '0 */6 * * *'"),
827
- schedule: z
828
- .boolean()
829
- .optional()
830
- .describe("Enable or disable the monitoring schedule"),
831
- }, async (args) => {
832
- try {
833
- trackMCP("percy_manage_visual_monitoring", server.server.getClientVersion(), config);
834
- return await percyManageVisualMonitoring(args, config);
835
- }
836
- catch (error) {
837
- return handleMCPError("percy_manage_visual_monitoring", server, config, error);
838
- }
839
- });
840
- // -------------------------------------------------------------------------
841
- // percy_trigger_ai_recompute
842
- // -------------------------------------------------------------------------
843
- tools.percy_trigger_ai_recompute = server.tool("percy_trigger_ai_recompute", "Re-run AI analysis with a custom prompt.", {
844
- build_id: z
845
- .string()
846
- .optional()
847
- .describe("Percy build ID (for bulk recompute)"),
848
- comparison_id: z
849
- .string()
850
- .optional()
851
- .describe("Single comparison ID to recompute"),
852
- prompt: z
853
- .string()
854
- .optional()
855
- .describe("Custom prompt for AI (max 400 chars), e.g. 'Ignore font rendering differences'"),
856
- mode: z
857
- .enum(["ignore", "unignore"])
858
- .optional()
859
- .describe("ignore = hide matching diffs, unignore = show matching diffs"),
860
- }, async (args) => {
861
- try {
862
- trackMCP("percy_trigger_ai_recompute", server.server.getClientVersion(), config);
863
- return await percyTriggerAiRecompute(args, config);
864
- }
865
- catch (error) {
866
- return handleMCPError("percy_trigger_ai_recompute", server, config, error);
867
- }
868
- });
869
- // -------------------------------------------------------------------------
870
- // percy_suggest_prompt
871
- // -------------------------------------------------------------------------
872
- tools.percy_suggest_prompt = server.tool("percy_suggest_prompt", "Get AI-suggested prompt for specific diff regions.", {
873
- comparison_id: z.string().describe("Percy comparison ID"),
874
- region_ids: z.string().describe("Comma-separated region IDs to analyze"),
875
- ignore_change: z
876
- .boolean()
877
- .optional()
878
- .describe("true = suggest ignore prompt, false = suggest show prompt (default true)"),
879
- }, async (args) => {
880
- try {
881
- trackMCP("percy_suggest_prompt", server.server.getClientVersion(), config);
882
- return await percySuggestPrompt(args, config);
883
- }
884
- catch (error) {
885
- return handleMCPError("percy_suggest_prompt", server, config, error);
886
- }
887
- });
888
- // -------------------------------------------------------------------------
889
- // percy_branchline_operations
890
- // -------------------------------------------------------------------------
891
- tools.percy_branchline_operations = server.tool("percy_branchline_operations", "Sync, merge, or unmerge branch baselines.", {
892
- action: z
893
- .enum(["sync", "merge", "unmerge"])
894
- .describe("Branchline operation to perform"),
895
- project_id: z.string().optional().describe("Percy project ID"),
896
- build_id: z.string().optional().describe("Percy build ID"),
897
- target_branch_filter: z
898
- .string()
899
- .optional()
900
- .describe("Target branch pattern for sync (e.g., 'main', 'release/*')"),
901
- snapshot_ids: z
902
- .string()
903
- .optional()
904
- .describe("Comma-separated snapshot IDs to include"),
905
- }, async (args) => {
906
- try {
907
- trackMCP("percy_branchline_operations", server.server.getClientVersion(), config);
908
- return await percyBranchlineOperations(args, config);
909
- }
910
- catch (error) {
911
- return handleMCPError("percy_branchline_operations", server, config, error);
912
- }
913
- });
914
- // =========================================================================
915
- // === FINALIZE / UPLOAD ===
916
- // =========================================================================
917
- // -------------------------------------------------------------------------
918
- // percy_finalize_build
919
- // -------------------------------------------------------------------------
920
- tools.percy_finalize_build = server.tool("percy_finalize_build", "Finalize a Percy build (triggers processing).", {
921
- build_id: z.string().describe("Percy build ID"),
922
- }, async (args) => {
923
- try {
924
- trackMCP("percy_finalize_build", server.server.getClientVersion(), config);
925
- return await percyFinalizeBuild(args, config);
926
- }
927
- catch (error) {
928
- return handleMCPError("percy_finalize_build", server, config, error);
929
- }
930
- });
931
- // -------------------------------------------------------------------------
932
- // percy_finalize_snapshot
933
- // -------------------------------------------------------------------------
934
- tools.percy_finalize_snapshot = server.tool("percy_finalize_snapshot", "Finalize a snapshot (triggers rendering).", {
935
- snapshot_id: z.string().describe("Percy snapshot ID"),
936
- }, async (args) => {
937
- try {
938
- trackMCP("percy_finalize_snapshot", server.server.getClientVersion(), config);
939
- return await percyFinalizeSnapshot(args, config);
940
- }
941
- catch (error) {
942
- return handleMCPError("percy_finalize_snapshot", server, config, error);
943
- }
944
- });
945
- // -------------------------------------------------------------------------
946
- // percy_finalize_comparison
947
- // -------------------------------------------------------------------------
948
- tools.percy_finalize_comparison = server.tool("percy_finalize_comparison", "Finalize a comparison (triggers diff processing).", {
949
- comparison_id: z.string().describe("Percy comparison ID"),
950
- }, async (args) => {
951
- try {
952
- trackMCP("percy_finalize_comparison", server.server.getClientVersion(), config);
953
- return await percyFinalizeComparison(args, config);
954
- }
955
- catch (error) {
956
- return handleMCPError("percy_finalize_comparison", server, config, error);
957
- }
958
- });
959
- // -------------------------------------------------------------------------
960
- // percy_upload_resource
961
- // -------------------------------------------------------------------------
962
- tools.percy_upload_resource = server.tool("percy_upload_resource", "Upload a resource to a Percy build (CSS, JS, HTML, images).", {
963
- build_id: z.string().describe("Percy build ID"),
964
- sha: z.string().describe("SHA-256 hash of the resource content"),
965
- base64_content: z.string().describe("Base64-encoded resource content"),
966
- }, async (args) => {
967
- try {
968
- trackMCP("percy_upload_resource", server.server.getClientVersion(), config);
969
- return await percyUploadResource(args, config);
970
- }
971
- catch (error) {
972
- return handleMCPError("percy_upload_resource", server, config, error);
973
- }
974
- });
975
- // -------------------------------------------------------------------------
976
- // percy_upload_tile
977
- // -------------------------------------------------------------------------
978
- tools.percy_upload_tile = server.tool("percy_upload_tile", "Upload a screenshot tile to a comparison (PNG/JPEG).", {
979
- comparison_id: z.string().describe("Percy comparison ID"),
980
- base64_content: z
981
- .string()
982
- .describe("Base64-encoded PNG or JPEG screenshot"),
983
- }, async (args) => {
984
- try {
985
- trackMCP("percy_upload_tile", server.server.getClientVersion(), config);
986
- return await percyUploadTile(args, config);
987
- }
988
- catch (error) {
989
- return handleMCPError("percy_upload_tile", server, config, error);
990
- }
991
- });
992
- // -------------------------------------------------------------------------
993
- // percy_analyze_logs_realtime
994
- // -------------------------------------------------------------------------
995
- tools.percy_analyze_logs_realtime = server.tool("percy_analyze_logs_realtime", "Analyze raw logs in real-time without a stored build.", {
996
- logs: z
997
- .string()
998
- .describe('JSON array of log entries: [{"message":"...","level":"error","meta":{}}]'),
999
- }, async (args) => {
1000
- try {
1001
- trackMCP("percy_analyze_logs_realtime", server.server.getClientVersion(), config);
1002
- return await percyAnalyzeLogsRealtime(args, config);
1003
- }
1004
- catch (error) {
1005
- return handleMCPError("percy_analyze_logs_realtime", server, config, error);
1006
- }
1007
- });
1008
- // =========================================================================
1009
- // === WORKFLOWS (Composite — highest value) ===
1010
- // =========================================================================
1011
- // -------------------------------------------------------------------------
1012
- // percy_pr_visual_report
1013
- // -------------------------------------------------------------------------
1014
- tools.percy_pr_visual_report = server.tool("percy_pr_visual_report", "Get a complete PR visual regression report: risk-ranked changes with AI analysis and recommendations. THE tool for checking PR status.", {
1015
- project_id: z
1016
- .string()
1017
- .optional()
1018
- .describe("Percy project ID (optional if PERCY_TOKEN is project-scoped)"),
1019
- branch: z
1020
- .string()
1021
- .optional()
1022
- .describe("Git branch name to find the build"),
1023
- sha: z.string().optional().describe("Git commit SHA to find the build"),
1024
- build_id: z
1025
- .string()
1026
- .optional()
1027
- .describe("Direct Percy build ID (skips search)"),
1028
- }, async (args) => {
1029
- try {
1030
- trackMCP("percy_pr_visual_report", server.server.getClientVersion(), config);
1031
- return await percyPrVisualReport(args, config);
1032
- }
1033
- catch (error) {
1034
- return handleMCPError("percy_pr_visual_report", server, config, error);
1035
- }
1036
- });
1037
- // -------------------------------------------------------------------------
1038
- // percy_auto_triage
1039
- // -------------------------------------------------------------------------
1040
- tools.percy_auto_triage = server.tool("percy_auto_triage", "Auto-categorize all visual changes: Critical, Review Required, Auto-Approvable, Noise.", {
1041
- build_id: z.string().describe("Percy build ID"),
1042
- noise_threshold: z
1043
- .number()
1044
- .optional()
1045
- .describe("Diff ratio below this is noise (default 0.005 = 0.5%)"),
1046
- review_threshold: z
1047
- .number()
1048
- .optional()
1049
- .describe("Diff ratio above this needs review (default 0.15 = 15%)"),
1050
- }, async (args) => {
1051
- try {
1052
- trackMCP("percy_auto_triage", server.server.getClientVersion(), config);
1053
- return await percyAutoTriage(args, config);
1054
- }
1055
- catch (error) {
1056
- return handleMCPError("percy_auto_triage", server, config, error);
1057
- }
1058
- });
1059
- // -------------------------------------------------------------------------
1060
- // percy_debug_failed_build
1061
- // -------------------------------------------------------------------------
1062
- tools.percy_debug_failed_build = server.tool("percy_debug_failed_build", "Diagnose a failed build: cross-references logs, suggestions, and network issues with fix commands.", {
1063
- build_id: z.string().describe("Percy build ID"),
1064
- }, async (args) => {
1065
- try {
1066
- trackMCP("percy_debug_failed_build", server.server.getClientVersion(), config);
1067
- return await percyDebugFailedBuild(args, config);
1068
- }
1069
- catch (error) {
1070
- return handleMCPError("percy_debug_failed_build", server, config, error);
1071
- }
1072
- });
1073
- // -------------------------------------------------------------------------
1074
- // percy_diff_explain
1075
- // -------------------------------------------------------------------------
1076
- tools.percy_diff_explain = server.tool("percy_diff_explain", "Explain visual changes in plain English at 3 depth levels (summary/detailed/full_rca).", {
1077
- comparison_id: z.string().describe("Percy comparison ID"),
1078
- depth: z
1079
- .enum(["summary", "detailed", "full_rca"])
1080
- .optional()
1081
- .describe("Analysis depth (default: detailed)"),
1082
- }, async (args) => {
1083
- try {
1084
- trackMCP("percy_diff_explain", server.server.getClientVersion(), config);
1085
- return await percyDiffExplain(args, config);
1086
- }
1087
- catch (error) {
1088
- return handleMCPError("percy_diff_explain", server, config, error);
1089
- }
1090
- });
1091
- // -------------------------------------------------------------------------
1092
- // percy_snapshot_urls — Actually render URLs locally via Percy CLI
1093
- // -------------------------------------------------------------------------
1094
- tools.percy_snapshot_urls = server.tool("percy_snapshot_urls", "Snapshot URLs locally using Percy CLI. Launches a browser, captures screenshots at specified widths, and uploads to Percy. Runs in background — returns build URL immediately. Requires @percy/cli installed.", {
1095
- project_name: z
1096
- .string()
1097
- .describe("Percy project name (auto-creates if doesn't exist)"),
1098
- urls: z
1099
- .string()
1100
- .describe("Comma-separated URLs to snapshot, e.g. 'http://localhost:3000,http://localhost:3000/about'"),
1101
- widths: z
1102
- .string()
1103
- .optional()
1104
- .describe("Comma-separated widths (default: 375,1280)"),
1105
- type: z.string().optional().describe("Project type: web or automate"),
1106
- }, async (args) => {
1107
- try {
1108
- trackMCP("percy_snapshot_urls", server.server.getClientVersion(), config);
1109
- return await percySnapshotUrls(args, config);
1110
- }
1111
- catch (error) {
1112
- return handleMCPError("percy_snapshot_urls", server, config, error);
1113
- }
1114
- });
1115
- // -------------------------------------------------------------------------
1116
- // percy_run_tests — Run tests with Percy visual testing
1117
- // -------------------------------------------------------------------------
1118
- tools.percy_run_tests = server.tool("percy_run_tests", "Run a test command with Percy visual testing. Wraps your test command with percy exec to capture snapshots during test execution. Runs in background — returns build URL immediately. Requires @percy/cli installed.", {
1119
- project_name: z
1120
- .string()
1121
- .describe("Percy project name (auto-creates if doesn't exist)"),
1122
- test_command: z
1123
- .string()
1124
- .describe("Test command to run, e.g. 'npx cypress run' or 'npm test'"),
1125
- type: z.string().optional().describe("Project type: web or automate"),
1126
- }, async (args) => {
1127
- try {
1128
- trackMCP("percy_run_tests", server.server.getClientVersion(), config);
1129
- return await percyRunTests(args, config);
1130
- }
1131
- catch (error) {
1132
- return handleMCPError("percy_run_tests", server, config, error);
1133
- }
1134
- });
1135
- return tools;
1136
- }
1137
- export default registerPercyMcpTools;