@recapt/mcp 0.0.17-beta → 0.0.19-beta

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.
@@ -60,6 +60,10 @@ export function registerImprovementRunTools(server) {
60
60
  .enum(["running", "completed", "failed", "cancelled"])
61
61
  .optional()
62
62
  .describe("New status for the run"),
63
+ title: z
64
+ .string()
65
+ .optional()
66
+ .describe("A concise title summarizing what was fixed in this run (e.g., 'Fixed checkout button, improved mobile nav'). Set when completing the run."),
63
67
  phases: z
64
68
  .array(z.object({
65
69
  name: z.string(),
@@ -95,7 +99,7 @@ export function registerImprovementRunTools(server) {
95
99
  .optional()
96
100
  .describe("Total duration of the run in milliseconds"),
97
101
  }),
98
- }, async ({ run_id, status, phases, summary, completed_at, duration_ms, }) => {
102
+ }, async ({ run_id, status, title, phases, summary, completed_at, duration_ms, }) => {
99
103
  if (!isApiConfigured()) {
100
104
  return {
101
105
  content: [
@@ -109,6 +113,7 @@ export function registerImprovementRunTools(server) {
109
113
  }
110
114
  const { data, error } = await apiPatch(`/improvement-runs/${run_id}`, {
111
115
  status,
116
+ title,
112
117
  phases,
113
118
  summary,
114
119
  completed_at,
@@ -203,8 +208,30 @@ export function registerImprovementRunTools(server) {
203
208
  .string()
204
209
  .optional()
205
210
  .describe("Explanation for why the issue was dismissed (for dismissed/marked_intended actions)"),
211
+ page_path: z
212
+ .string()
213
+ .optional()
214
+ .describe("Page path affected by the fix (used for auto-creating remediation when remediation_id is not provided)"),
215
+ element_selector: z
216
+ .string()
217
+ .optional()
218
+ .describe("CSS selector of the affected element (used for auto-creating remediation)"),
219
+ diagnosis: z
220
+ .string()
221
+ .optional()
222
+ .describe("Root cause analysis (used for auto-creating remediation; defaults to hypothesis if not provided)"),
223
+ proposed_fix: z
224
+ .string()
225
+ .optional()
226
+ .describe("Fix description (used for auto-creating remediation; defaults to expected_improvement if not provided)"),
227
+ confidence: z
228
+ .number()
229
+ .min(0)
230
+ .max(1)
231
+ .optional()
232
+ .describe("Fix confidence 0-1 (used for auto-creating remediation; defaults to 0.7)"),
206
233
  }),
207
- }, async ({ run_id, issue_id, action_type, hypothesis, expected_improvement, code_changes, pr_url, pr_number, remediation_id, deferral_reason, dismissal_reason, }) => {
234
+ }, async ({ run_id, issue_id, action_type, hypothesis, expected_improvement, code_changes, pr_url, pr_number, remediation_id, deferral_reason, dismissal_reason, page_path, element_selector, diagnosis, proposed_fix, confidence, }) => {
208
235
  if (!isApiConfigured()) {
209
236
  return {
210
237
  content: [
@@ -227,6 +254,50 @@ export function registerImprovementRunTools(server) {
227
254
  remediation_id,
228
255
  deferral_reason,
229
256
  dismissal_reason,
257
+ page_path,
258
+ element_selector,
259
+ diagnosis,
260
+ proposed_fix,
261
+ confidence,
262
+ });
263
+ if (error) {
264
+ return {
265
+ content: [{ type: "text", text: JSON.stringify({ error }) }],
266
+ isError: true,
267
+ };
268
+ }
269
+ return { content: [{ type: "text", text: JSON.stringify(data) }] };
270
+ });
271
+ server.registerTool("update_improvement_action", {
272
+ description: "Update an existing improvement run action with PR information. Use this after a PR has been created to link it to the action. " +
273
+ "This is especially useful in GitHub Actions workflows where the PR is created after the action is recorded.",
274
+ inputSchema: z.object({
275
+ run_id: z.string().describe("The ID of the improvement run"),
276
+ action_id: z.string().describe("The ID of the action to update"),
277
+ pr_url: z
278
+ .string()
279
+ .optional()
280
+ .describe("GitHub PR URL to link to this action"),
281
+ pr_number: z
282
+ .number()
283
+ .optional()
284
+ .describe("GitHub PR number to link to this action"),
285
+ }),
286
+ }, async ({ run_id, action_id, pr_url, pr_number, }) => {
287
+ if (!isApiConfigured()) {
288
+ return {
289
+ content: [
290
+ {
291
+ type: "text",
292
+ text: JSON.stringify({ error: "API not configured" }),
293
+ },
294
+ ],
295
+ isError: true,
296
+ };
297
+ }
298
+ const { data, error } = await apiPatch(`/improvement-runs/${run_id}/actions/${action_id}`, {
299
+ pr_url,
300
+ pr_number,
230
301
  });
231
302
  if (error) {
232
303
  return {
@@ -89,6 +89,8 @@ export function registerRemediationTools(server) {
89
89
  status: z
90
90
  .enum([
91
91
  "proposed",
92
+ "waiting",
93
+ "dismissed",
92
94
  "deployed",
93
95
  "evaluating",
94
96
  "succeeded",
@@ -220,4 +222,114 @@ export function registerRemediationTools(server) {
220
222
  }
221
223
  return { content: [{ type: "text", text: JSON.stringify(data) }] };
222
224
  });
225
+ server.registerTool("update_remediation_status", {
226
+ description: "Update the status of a remediation based on PR events. Use to mark a fix as 'waiting' (PR created), 'deployed' (PR merged), or 'dismissed' (PR closed without merge).",
227
+ inputSchema: z.object({
228
+ remediation_id: z
229
+ .string()
230
+ .describe("The ID of the remediation to update"),
231
+ status: z
232
+ .enum(["waiting", "deployed", "dismissed"])
233
+ .describe("New status: 'waiting' = PR open, 'deployed' = PR merged, 'dismissed' = PR closed without merge"),
234
+ pr_url: z.string().optional().describe("URL of the pull request"),
235
+ pr_number: z.number().optional().describe("PR number"),
236
+ pr_merged_at: z
237
+ .string()
238
+ .optional()
239
+ .describe("ISO timestamp when PR was merged"),
240
+ pr_closed_at: z
241
+ .string()
242
+ .optional()
243
+ .describe("ISO timestamp when PR was closed"),
244
+ }),
245
+ }, async ({ remediation_id, status, pr_url, pr_number, pr_merged_at, pr_closed_at, }) => {
246
+ if (!isApiConfigured()) {
247
+ return {
248
+ content: [
249
+ {
250
+ type: "text",
251
+ text: JSON.stringify({ error: "API not configured" }),
252
+ },
253
+ ],
254
+ isError: true,
255
+ };
256
+ }
257
+ const { data, error } = await apiPatch(`/remediations/${remediation_id}/status`, {
258
+ status,
259
+ pr_url,
260
+ pr_number,
261
+ pr_merged_at,
262
+ pr_closed_at,
263
+ });
264
+ if (error) {
265
+ return {
266
+ content: [{ type: "text", text: JSON.stringify({ error }) }],
267
+ isError: true,
268
+ };
269
+ }
270
+ return { content: [{ type: "text", text: JSON.stringify(data) }] };
271
+ });
272
+ server.registerTool("list_remediations_by_status", {
273
+ description: "List remediations filtered by one or more statuses. Use to find all 'waiting' PRs or 'deployed' fixes ready for evaluation.",
274
+ inputSchema: z.object({
275
+ statuses: z
276
+ .array(z.enum([
277
+ "proposed",
278
+ "waiting",
279
+ "dismissed",
280
+ "deployed",
281
+ "evaluating",
282
+ "succeeded",
283
+ "failed",
284
+ "reverted",
285
+ ]))
286
+ .describe("List of statuses to filter by"),
287
+ }),
288
+ }, async ({ statuses }) => {
289
+ if (!isApiConfigured()) {
290
+ return {
291
+ content: [
292
+ {
293
+ type: "text",
294
+ text: JSON.stringify({ error: "API not configured" }),
295
+ },
296
+ ],
297
+ isError: true,
298
+ };
299
+ }
300
+ const { data, error } = await apiGet(`/remediations/by-status`, { statuses: statuses.join(",") });
301
+ if (error) {
302
+ return {
303
+ content: [{ type: "text", text: JSON.stringify({ error }) }],
304
+ isError: true,
305
+ };
306
+ }
307
+ return { content: [{ type: "text", text: JSON.stringify(data) }] };
308
+ });
309
+ server.registerTool("get_remediation_by_pr", {
310
+ description: "Get a remediation by its PR number. Use to look up fix details when processing PR events.",
311
+ inputSchema: z.object({
312
+ pr_number: z.number().describe("The PR number to look up"),
313
+ }),
314
+ }, async ({ pr_number }) => {
315
+ if (!isApiConfigured()) {
316
+ return {
317
+ content: [
318
+ {
319
+ type: "text",
320
+ text: JSON.stringify({ error: "API not configured" }),
321
+ },
322
+ ],
323
+ isError: true,
324
+ };
325
+ }
326
+ const { data, error } = await apiGet(`/remediations/by-pr/${pr_number}`);
327
+ if (error) {
328
+ return {
329
+ content: [{ type: "text", text: JSON.stringify({ error }) }],
330
+ isError: true,
331
+ };
332
+ }
333
+ return { content: [{ type: "text", text: JSON.stringify(data) }] };
334
+ });
223
335
  }
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@recapt/mcp",
3
- "version": "0.0.17-beta",
3
+ "version": "0.0.19-beta",
4
4
  "description": "MCP exposing recapt behavioral intelligence to AI coding agents",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "type": "module",
8
8
  "scripts": {
9
- "build": "npm run generate-catalog && tsc && cp src/tools/catalog/toolCatalog.json dist/tools/catalog/",
9
+ "build": "npm run generate-catalog && tsc && cp src/tools/catalog/toolCatalog.json src/tools/catalog/anthropicToolCatalog.json dist/tools/catalog/",
10
+ "build:workflows": "tsx scripts/buildWorkflows.ts",
10
11
  "clean": "rimraf ./dist",
11
12
  "dev": "tsx --watch src/index.ts",
12
13
  "start": "node dist/index.js",
@@ -27,6 +28,7 @@
27
28
  "author": "Recapt",
28
29
  "license": "ISC",
29
30
  "dependencies": {
31
+ "@glimt/mcp-tools": "file:../../libraries/mcp-tools",
30
32
  "@inquirer/prompts": "^8.3.2",
31
33
  "@modelcontextprotocol/sdk": "^1.12.0",
32
34
  "commander": "^14.0.3",
@@ -42,5 +44,8 @@
42
44
  "rimraf": "^6.0.1",
43
45
  "tsx": "^4.16.5",
44
46
  "typescript": "5.9.3"
47
+ },
48
+ "devDependencies": {
49
+ "yaml": "^2.8.3"
45
50
  }
46
51
  }