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

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,182 +0,0 @@
1
- /**
2
- * percy_manage_ignored_regions — Create, list, save, or delete ignored regions
3
- * on Percy comparisons.
4
- *
5
- * Supports bounding box (raw), XPath, CSS selector, and fullpage types.
6
- */
7
- import { PercyClient } from "../../../lib/percy-api/client.js";
8
- export async function percyManageIgnoredRegions(args, config) {
9
- const { comparison_id, action = "list", region_id, type, coordinates, selector, } = args;
10
- const client = new PercyClient(config);
11
- // ---- List ----
12
- if (action === "list") {
13
- if (!comparison_id) {
14
- return {
15
- content: [
16
- {
17
- type: "text",
18
- text: "comparison_id is required for the 'list' action.",
19
- },
20
- ],
21
- isError: true,
22
- };
23
- }
24
- const response = await client.get("/region-revisions", {
25
- comparison_id,
26
- });
27
- const regions = Array.isArray(response?.data) ? response.data : [];
28
- if (regions.length === 0) {
29
- return {
30
- content: [
31
- { type: "text", text: "_No ignored regions for this comparison._" },
32
- ],
33
- };
34
- }
35
- const lines = [];
36
- lines.push(`## Ignored Regions (Comparison: ${comparison_id})`);
37
- lines.push("");
38
- lines.push("| ID | Type | Selector / Coordinates |");
39
- lines.push("|----|------|------------------------|");
40
- for (const region of regions) {
41
- const attrs = region.attributes ?? region;
42
- const rType = attrs.type ?? attrs["region-type"] ?? "unknown";
43
- const rSelector = attrs.selector ?? "";
44
- const rCoords = attrs.coordinates
45
- ? JSON.stringify(attrs.coordinates)
46
- : "";
47
- const display = rSelector || rCoords || "—";
48
- lines.push(`| ${region.id ?? "?"} | ${rType} | ${display} |`);
49
- }
50
- return { content: [{ type: "text", text: lines.join("\n") }] };
51
- }
52
- // ---- Create ----
53
- if (action === "create") {
54
- if (!comparison_id) {
55
- return {
56
- content: [
57
- {
58
- type: "text",
59
- text: "comparison_id is required for the 'create' action.",
60
- },
61
- ],
62
- isError: true,
63
- };
64
- }
65
- const attrs = {};
66
- if (type)
67
- attrs["region-type"] = type;
68
- if (selector)
69
- attrs.selector = selector;
70
- if (coordinates) {
71
- try {
72
- attrs.coordinates = JSON.parse(coordinates);
73
- }
74
- catch {
75
- return {
76
- content: [
77
- {
78
- type: "text",
79
- text: 'Invalid coordinates JSON. Expected format: {"x":0,"y":0,"width":100,"height":100}',
80
- },
81
- ],
82
- isError: true,
83
- };
84
- }
85
- }
86
- const body = {
87
- data: {
88
- type: "region-revisions",
89
- attributes: attrs,
90
- relationships: {
91
- comparison: {
92
- data: { type: "comparisons", id: comparison_id },
93
- },
94
- },
95
- },
96
- };
97
- try {
98
- const result = (await client.post("/region-revisions", body));
99
- const id = result?.data?.id ?? "?";
100
- return {
101
- content: [
102
- {
103
- type: "text",
104
- text: `Ignored region created (ID: ${id}, type: ${type ?? "raw"}).`,
105
- },
106
- ],
107
- };
108
- }
109
- catch (error) {
110
- const message = error instanceof Error ? error.message : String(error);
111
- return {
112
- content: [
113
- { type: "text", text: `Failed to create ignored region: ${message}` },
114
- ],
115
- isError: true,
116
- };
117
- }
118
- }
119
- // ---- Save (bulk) ----
120
- if (action === "save") {
121
- try {
122
- await client.patch("/region-revisions/bulk-save", {});
123
- return {
124
- content: [
125
- {
126
- type: "text",
127
- text: "Ignored regions saved (bulk save completed).",
128
- },
129
- ],
130
- };
131
- }
132
- catch (error) {
133
- const message = error instanceof Error ? error.message : String(error);
134
- return {
135
- content: [
136
- { type: "text", text: `Failed to bulk-save regions: ${message}` },
137
- ],
138
- isError: true,
139
- };
140
- }
141
- }
142
- // ---- Delete ----
143
- if (action === "delete") {
144
- if (!region_id) {
145
- return {
146
- content: [
147
- {
148
- type: "text",
149
- text: "region_id is required for the 'delete' action.",
150
- },
151
- ],
152
- isError: true,
153
- };
154
- }
155
- try {
156
- await client.del(`/region-revisions/${region_id}`);
157
- return {
158
- content: [
159
- { type: "text", text: `Ignored region ${region_id} deleted.` },
160
- ],
161
- };
162
- }
163
- catch (error) {
164
- const message = error instanceof Error ? error.message : String(error);
165
- return {
166
- content: [
167
- { type: "text", text: `Failed to delete region: ${message}` },
168
- ],
169
- isError: true,
170
- };
171
- }
172
- }
173
- return {
174
- content: [
175
- {
176
- type: "text",
177
- text: `Invalid action "${action}". Valid actions: list, create, save, delete`,
178
- },
179
- ],
180
- isError: true,
181
- };
182
- }
@@ -1,16 +0,0 @@
1
- /**
2
- * percy_manage_project_settings — View or update Percy project settings.
3
- *
4
- * GET /projects/{project_id} to read current settings.
5
- * PATCH /projects/{project_id} with JSON:API body to update.
6
- * High-risk attributes require confirm_destructive=true.
7
- */
8
- import { BrowserStackConfig } from "../../../lib/types.js";
9
- import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
10
- interface ManageProjectSettingsArgs {
11
- project_id: string;
12
- settings?: string;
13
- confirm_destructive?: boolean;
14
- }
15
- export declare function percyManageProjectSettings(args: ManageProjectSettingsArgs, config: BrowserStackConfig): Promise<CallToolResult>;
16
- export {};
@@ -1,97 +0,0 @@
1
- /**
2
- * percy_manage_project_settings — View or update Percy project settings.
3
- *
4
- * GET /projects/{project_id} to read current settings.
5
- * PATCH /projects/{project_id} with JSON:API body to update.
6
- * High-risk attributes require confirm_destructive=true.
7
- */
8
- import { PercyClient } from "../../../lib/percy-api/client.js";
9
- // ---------------------------------------------------------------------------
10
- // Constants
11
- // ---------------------------------------------------------------------------
12
- const HIGH_RISK_ATTRIBUTES = [
13
- "auto-approve-branch-filter",
14
- "approval-required-branch-filter",
15
- ];
16
- export async function percyManageProjectSettings(args, config) {
17
- const { project_id, settings, confirm_destructive } = args;
18
- const client = new PercyClient(config);
19
- // ---- Read current settings ----
20
- const current = (await client.get(`/projects/${project_id}`));
21
- if (!settings) {
22
- // Read-only mode — return current settings
23
- const attrs = current?.data?.attributes ?? current?.data ?? {};
24
- const lines = [];
25
- lines.push(`## Project Settings (ID: ${project_id})`);
26
- lines.push("");
27
- lines.push("| Setting | Value |");
28
- lines.push("|---------|-------|");
29
- for (const [key, value] of Object.entries(attrs)) {
30
- lines.push(`| ${key} | ${JSON.stringify(value)} |`);
31
- }
32
- return { content: [{ type: "text", text: lines.join("\n") }] };
33
- }
34
- // ---- Update mode ----
35
- let parsed;
36
- try {
37
- parsed = JSON.parse(settings);
38
- }
39
- catch {
40
- return {
41
- content: [
42
- {
43
- type: "text",
44
- text: "Invalid settings JSON. Provide a valid JSON object of attributes to update.",
45
- },
46
- ],
47
- isError: true,
48
- };
49
- }
50
- // Check for high-risk attributes
51
- const highRiskKeys = Object.keys(parsed).filter((key) => HIGH_RISK_ATTRIBUTES.includes(key));
52
- if (highRiskKeys.length > 0 && !confirm_destructive) {
53
- const lines = [];
54
- lines.push("## Warning: High-Risk Settings Change");
55
- lines.push("");
56
- lines.push("The following settings can significantly affect your workflow:");
57
- lines.push("");
58
- for (const key of highRiskKeys) {
59
- lines.push(`- **${key}**: \`${JSON.stringify(parsed[key])}\``);
60
- }
61
- lines.push("");
62
- lines.push("Set `confirm_destructive=true` to apply these changes.");
63
- return { content: [{ type: "text", text: lines.join("\n") }] };
64
- }
65
- // Build JSON:API PATCH body
66
- const body = {
67
- data: {
68
- type: "projects",
69
- id: project_id,
70
- attributes: parsed,
71
- },
72
- };
73
- try {
74
- const result = (await client.patch(`/projects/${project_id}`, body));
75
- const updatedAttrs = result?.data?.attributes ?? result?.data ?? {};
76
- const lines = [];
77
- lines.push(`## Project Settings Updated (ID: ${project_id})`);
78
- lines.push("");
79
- lines.push("**Updated attributes:**");
80
- for (const key of Object.keys(parsed)) {
81
- lines.push(`- **${key}**: ${JSON.stringify(updatedAttrs[key] ?? parsed[key])}`);
82
- }
83
- return { content: [{ type: "text", text: lines.join("\n") }] };
84
- }
85
- catch (error) {
86
- const message = error instanceof Error ? error.message : String(error);
87
- return {
88
- content: [
89
- {
90
- type: "text",
91
- text: `Failed to update project settings: ${message}`,
92
- },
93
- ],
94
- isError: true,
95
- };
96
- }
97
- }
@@ -1,14 +0,0 @@
1
- /**
2
- * percy_manage_tokens — List or rotate Percy project tokens.
3
- *
4
- * Token values are masked — only the last 4 characters are shown.
5
- */
6
- import { BrowserStackConfig } from "../../../lib/types.js";
7
- import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
8
- interface ManageTokensArgs {
9
- project_id: string;
10
- action?: string;
11
- role?: string;
12
- }
13
- export declare function percyManageTokens(args: ManageTokensArgs, config: BrowserStackConfig): Promise<CallToolResult>;
14
- export {};
@@ -1,90 +0,0 @@
1
- /**
2
- * percy_manage_tokens — List or rotate Percy project tokens.
3
- *
4
- * Token values are masked — only the last 4 characters are shown.
5
- */
6
- import { PercyClient } from "../../../lib/percy-api/client.js";
7
- export async function percyManageTokens(args, config) {
8
- const { project_id, action = "list", role } = args;
9
- const client = new PercyClient(config);
10
- // ---- List ----
11
- if (action === "list") {
12
- const response = await client.get(`/projects/${project_id}/tokens`);
13
- const tokens = Array.isArray(response?.data) ? response.data : [];
14
- if (tokens.length === 0) {
15
- return {
16
- content: [
17
- { type: "text", text: "_No tokens found for this project._" },
18
- ],
19
- };
20
- }
21
- const lines = [];
22
- lines.push(`## Tokens for Project ${project_id}`);
23
- lines.push("");
24
- lines.push("| Role | Token (masked) | ID |");
25
- lines.push("|------|---------------|----|");
26
- for (const token of tokens) {
27
- const attrs = token.attributes ?? token;
28
- const tokenRole = attrs.role ?? attrs["token-role"] ?? "unknown";
29
- const tokenValue = attrs.token ?? attrs["token-value"] ?? "";
30
- const masked = tokenValue.length > 4 ? `****${tokenValue.slice(-4)}` : "****";
31
- lines.push(`| ${tokenRole} | ${masked} | ${token.id ?? "?"} |`);
32
- }
33
- lines.push("");
34
- lines.push("_Token values are masked for security. Use action='rotate' to generate a new token._");
35
- return { content: [{ type: "text", text: lines.join("\n") }] };
36
- }
37
- // ---- Rotate ----
38
- if (action === "rotate") {
39
- if (!role) {
40
- return {
41
- content: [
42
- {
43
- type: "text",
44
- text: "role is required for the 'rotate' action (e.g., 'write', 'read').",
45
- },
46
- ],
47
- isError: true,
48
- };
49
- }
50
- const body = {
51
- data: {
52
- type: "tokens",
53
- attributes: {
54
- "project-id": parseInt(project_id, 10),
55
- role,
56
- },
57
- },
58
- };
59
- try {
60
- const result = (await client.patch("/tokens/rotate", body));
61
- const attrs = result?.data?.attributes ?? result?.data ?? {};
62
- const newToken = attrs.token ?? attrs["token-value"] ?? "";
63
- const masked = newToken.length > 4 ? `****${newToken.slice(-4)}` : "****";
64
- return {
65
- content: [
66
- {
67
- type: "text",
68
- text: `## Token Rotated\n\n**Role:** ${role}\n**New token (masked):** ${masked}\n\n_The full token was returned by the API. Store it securely — it cannot be retrieved again._`,
69
- },
70
- ],
71
- };
72
- }
73
- catch (error) {
74
- const message = error instanceof Error ? error.message : String(error);
75
- return {
76
- content: [{ type: "text", text: `Failed to rotate token: ${message}` }],
77
- isError: true,
78
- };
79
- }
80
- }
81
- return {
82
- content: [
83
- {
84
- type: "text",
85
- text: `Invalid action "${action}". Valid actions: list, rotate`,
86
- },
87
- ],
88
- isError: true,
89
- };
90
- }
@@ -1,15 +0,0 @@
1
- /**
2
- * percy_manage_webhooks — Create, update, list, or delete webhooks for Percy build events.
3
- */
4
- import { BrowserStackConfig } from "../../../lib/types.js";
5
- import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
6
- interface ManageWebhooksArgs {
7
- project_id: string;
8
- action?: string;
9
- webhook_id?: string;
10
- url?: string;
11
- events?: string;
12
- description?: string;
13
- }
14
- export declare function percyManageWebhooks(args: ManageWebhooksArgs, config: BrowserStackConfig): Promise<CallToolResult>;
15
- export {};
@@ -1,180 +0,0 @@
1
- /**
2
- * percy_manage_webhooks — Create, update, list, or delete webhooks for Percy build events.
3
- */
4
- import { PercyClient } from "../../../lib/percy-api/client.js";
5
- export async function percyManageWebhooks(args, config) {
6
- const { project_id, action = "list", webhook_id, url, events, description, } = args;
7
- const client = new PercyClient(config);
8
- // ---- List ----
9
- if (action === "list") {
10
- const response = await client.get(`/webhook-configs`, {
11
- "filter[project-id]": project_id,
12
- });
13
- const webhooks = Array.isArray(response?.data) ? response.data : [];
14
- if (webhooks.length === 0) {
15
- return {
16
- content: [
17
- { type: "text", text: "_No webhooks configured for this project._" },
18
- ],
19
- };
20
- }
21
- const lines = [];
22
- lines.push(`## Webhooks for Project ${project_id}`);
23
- lines.push("");
24
- lines.push("| ID | URL | Events | Description |");
25
- lines.push("|----|-----|--------|-------------|");
26
- for (const webhook of webhooks) {
27
- const attrs = webhook.attributes ?? webhook;
28
- const wUrl = attrs.url ?? "?";
29
- const wEvents = Array.isArray(attrs.events)
30
- ? attrs.events.join(", ")
31
- : (attrs.events ?? "?");
32
- const wDesc = attrs.description ?? "";
33
- lines.push(`| ${webhook.id ?? "?"} | ${wUrl} | ${wEvents} | ${wDesc} |`);
34
- }
35
- return { content: [{ type: "text", text: lines.join("\n") }] };
36
- }
37
- // ---- Create ----
38
- if (action === "create") {
39
- if (!url) {
40
- return {
41
- content: [
42
- { type: "text", text: "url is required for the 'create' action." },
43
- ],
44
- isError: true,
45
- };
46
- }
47
- const eventArray = events
48
- ? events
49
- .split(",")
50
- .map((e) => e.trim())
51
- .filter(Boolean)
52
- : [];
53
- const body = {
54
- data: {
55
- type: "webhook-configs",
56
- attributes: {
57
- url,
58
- events: eventArray,
59
- ...(description ? { description } : {}),
60
- },
61
- relationships: {
62
- project: { data: { type: "projects", id: project_id } },
63
- },
64
- },
65
- };
66
- try {
67
- const result = (await client.post("/webhook-configs", body));
68
- const id = result?.data?.id ?? "?";
69
- return {
70
- content: [
71
- {
72
- type: "text",
73
- text: `## Webhook Created\n\n**ID:** ${id}\n**URL:** ${url}\n**Events:** ${eventArray.join(", ") || "all"}\n${description ? `**Description:** ${description}` : ""}`,
74
- },
75
- ],
76
- };
77
- }
78
- catch (error) {
79
- const message = error instanceof Error ? error.message : String(error);
80
- return {
81
- content: [
82
- { type: "text", text: `Failed to create webhook: ${message}` },
83
- ],
84
- isError: true,
85
- };
86
- }
87
- }
88
- // ---- Update ----
89
- if (action === "update") {
90
- if (!webhook_id) {
91
- return {
92
- content: [
93
- {
94
- type: "text",
95
- text: "webhook_id is required for the 'update' action.",
96
- },
97
- ],
98
- isError: true,
99
- };
100
- }
101
- const attrs = {};
102
- if (url)
103
- attrs.url = url;
104
- if (events) {
105
- attrs.events = events
106
- .split(",")
107
- .map((e) => e.trim())
108
- .filter(Boolean);
109
- }
110
- if (description)
111
- attrs.description = description;
112
- const body = {
113
- data: {
114
- type: "webhook-configs",
115
- id: webhook_id,
116
- attributes: attrs,
117
- },
118
- };
119
- try {
120
- await client.patch(`/webhook-configs/${webhook_id}`, body);
121
- return {
122
- content: [
123
- {
124
- type: "text",
125
- text: `Webhook ${webhook_id} updated successfully.`,
126
- },
127
- ],
128
- };
129
- }
130
- catch (error) {
131
- const message = error instanceof Error ? error.message : String(error);
132
- return {
133
- content: [
134
- { type: "text", text: `Failed to update webhook: ${message}` },
135
- ],
136
- isError: true,
137
- };
138
- }
139
- }
140
- // ---- Delete ----
141
- if (action === "delete") {
142
- if (!webhook_id) {
143
- return {
144
- content: [
145
- {
146
- type: "text",
147
- text: "webhook_id is required for the 'delete' action.",
148
- },
149
- ],
150
- isError: true,
151
- };
152
- }
153
- try {
154
- await client.del(`/webhook-configs/${webhook_id}`);
155
- return {
156
- content: [
157
- { type: "text", text: `Webhook ${webhook_id} deleted successfully.` },
158
- ],
159
- };
160
- }
161
- catch (error) {
162
- const message = error instanceof Error ? error.message : String(error);
163
- return {
164
- content: [
165
- { type: "text", text: `Failed to delete webhook: ${message}` },
166
- ],
167
- isError: true,
168
- };
169
- }
170
- }
171
- return {
172
- content: [
173
- {
174
- type: "text",
175
- text: `Invalid action "${action}". Valid actions: list, create, update, delete`,
176
- },
177
- ],
178
- isError: true,
179
- };
180
- }
@@ -1,3 +0,0 @@
1
- import { BrowserStackConfig } from "../../../lib/types.js";
2
- import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
3
- export declare function percyAuthStatusV2(_args: Record<string, never>, config: BrowserStackConfig): Promise<CallToolResult>;
@@ -1,80 +0,0 @@
1
- import { percyGet } from "../../../lib/percy-api/percy-auth.js";
2
- import { getSession, formatActiveProject, formatActiveBuild, } from "../../../lib/percy-api/percy-session.js";
3
- export async function percyAuthStatusV2(_args, config) {
4
- let output = `## Percy Auth Status\n\n`;
5
- const hasCreds = !!(config["browserstack-username"] && config["browserstack-access-key"]);
6
- output += `| Credential | Status |\n|---|---|\n`;
7
- output += `| BrowserStack Username | ${hasCreds ? config["browserstack-username"] : "Not set"} |\n`;
8
- output += `| BrowserStack Access Key | ${hasCreds ? "Set" : "Not set"} |\n`;
9
- output += "\n";
10
- // Note about PERCY_TOKEN — it's per-project, not global
11
- output += `> **Note:** PERCY_TOKEN is set per-project, not globally. Use \`percy_create_project\` to get a project token — it will be activated automatically for subsequent calls.\n\n`;
12
- if (hasCreds) {
13
- output += `### Validation\n\n`;
14
- // Test BrowserStack API by checking user info (lightweight, won't 500)
15
- const bsAuth = Buffer.from(`${config["browserstack-username"]}:${config["browserstack-access-key"]}`).toString("base64");
16
- try {
17
- const response = await fetch("https://api.browserstack.com/api/app_percy/user", { headers: { Authorization: `Basic ${bsAuth}` } });
18
- if (response.ok) {
19
- const userData = await response.json();
20
- const orgName = userData?.organizations?.[0]?.name;
21
- const orgId = userData?.organizations?.[0]?.id;
22
- output += `**BrowserStack API:** Connected\n`;
23
- if (orgName)
24
- output += `**Organization:** ${orgName}`;
25
- if (orgId)
26
- output += ` (ID: ${orgId})`;
27
- output += `\n`;
28
- }
29
- else {
30
- output += `**BrowserStack API:** ${response.status} ${response.statusText}\n`;
31
- }
32
- }
33
- catch (e) {
34
- output += `**BrowserStack API:** Failed — ${e.message}\n`;
35
- }
36
- // Test Percy API read access (use a lightweight endpoint)
37
- try {
38
- await percyGet("/organizations", config, { "page[limit]": "1" });
39
- output += `**Percy API (Basic Auth):** Connected\n`;
40
- }
41
- catch (e) {
42
- // If /organizations fails, try a simpler endpoint
43
- try {
44
- await percyGet("/user", config);
45
- output += `**Percy API (Basic Auth):** Connected\n`;
46
- }
47
- catch {
48
- output += `**Percy API (Basic Auth):** Limited — ${e.message}\n`;
49
- output += `This is OK. All project-scoped tools work via BrowserStack API.\n`;
50
- }
51
- }
52
- }
53
- output += "\n### Capabilities\n\n";
54
- if (hasCreds) {
55
- output += `All Percy MCP tools are available:\n`;
56
- output += `- Create/manage projects and tokens\n`;
57
- output += `- Create builds (URL, screenshot, app BYOS)\n`;
58
- output += `- Read builds, snapshots, comparisons\n`;
59
- output += `- AI analysis, RCA, insights\n`;
60
- output += `- Clone builds, Figma integration\n`;
61
- }
62
- else {
63
- output += `No BrowserStack credentials found.\n\n`;
64
- output += `Set your credentials in MCP server config or environment:\n`;
65
- output += `\`\`\`bash\nexport BROWSERSTACK_USERNAME="your_username"\nexport BROWSERSTACK_ACCESS_KEY="your_key"\n\`\`\`\n`;
66
- }
67
- // Show active session context
68
- const session = getSession();
69
- if (session.projectName || session.buildId) {
70
- output += `\n### Active Session\n`;
71
- output += formatActiveProject();
72
- output += formatActiveBuild();
73
- }
74
- output += `\n### Getting Started\n\n`;
75
- output += `1. \`percy_create_project\` — Create/access a project (sets active token)\n`;
76
- output += `2. \`percy_create_build\` — Create a web build with URLs or screenshots\n`;
77
- output += `3. \`percy_create_app_build\` — Create an app BYOS build (works with sample data)\n`;
78
- output += `4. \`percy_get_projects\` — List all projects in your org\n`;
79
- return { content: [{ type: "text", text: output }] };
80
- }