@recapt/mcp 0.0.4-beta → 0.0.6-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.
- package/dist/api/client.js +24 -75
- package/dist/cli/commands/setup.d.ts +7 -0
- package/dist/cli/commands/setup.js +180 -0
- package/dist/cli/commands/skill.d.ts +23 -0
- package/dist/cli/commands/skill.js +251 -0
- package/dist/cli/index.d.ts +11 -0
- package/dist/cli/index.js +24 -0
- package/dist/cli/skill.d.ts +14 -0
- package/dist/cli/skill.js +249 -0
- package/dist/cli/utils/ide-config.d.ts +31 -0
- package/dist/cli/utils/ide-config.js +290 -0
- package/dist/cli/utils/prompts.d.ts +22 -0
- package/dist/cli/utils/prompts.js +133 -0
- package/dist/index.d.ts +12 -1
- package/dist/index.js +233 -260
- package/dist/tools/catalog/callTool.d.ts +22 -0
- package/dist/tools/catalog/callTool.js +92 -0
- package/dist/tools/catalog/index.d.ts +11 -0
- package/dist/tools/catalog/index.js +11 -0
- package/dist/tools/catalog/searchTools.d.ts +22 -0
- package/dist/tools/catalog/searchTools.js +194 -0
- package/dist/tools/catalog/toolCatalog.json +16246 -0
- package/package.json +12 -6
- package/skills/deep-dive.md +92 -0
- package/skills/regression-hunt.md +120 -0
- package/skills/self-healing.md +95 -0
package/dist/index.js
CHANGED
|
@@ -3,62 +3,216 @@
|
|
|
3
3
|
* MCP Server entry point.
|
|
4
4
|
*
|
|
5
5
|
* Exposes recapt behavioral intelligence as tools for AI coding agents.
|
|
6
|
-
*
|
|
6
|
+
* Uses a search_tools + call_tool pattern to minimize context while
|
|
7
|
+
* providing access to 40+ analysis tools.
|
|
8
|
+
*
|
|
9
|
+
* Exposed tools (10):
|
|
10
|
+
* - search_tools: Discover tools by intent
|
|
11
|
+
* - call_tool: Execute discovered tools
|
|
12
|
+
* - get_domains: List tracked domains
|
|
13
|
+
* - run_full_diagnostic: Self-healing entry point
|
|
14
|
+
* - triage_sessions: Find sessions needing attention
|
|
15
|
+
* - memory_save, memory_recall, memory_list, memory_delete, memory_clear
|
|
16
|
+
*
|
|
17
|
+
* Hidden tools (38): Accessible via call_tool after discovery with search_tools
|
|
7
18
|
*/
|
|
8
19
|
import "dotenv/config";
|
|
9
20
|
// @ts-ignore - MCP SDK types are complex
|
|
10
21
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
11
22
|
// @ts-ignore - MCP SDK types are complex
|
|
12
23
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
13
|
-
import { isApiConfigured, getApiUrl } from "./api/client.js";
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
import { registerGetSessionDetails } from "./tools/getSessionDetails.js";
|
|
19
|
-
import { registerGetPageTrends } from "./tools/getPageTrends.js";
|
|
20
|
-
import { registerGetAnomalies } from "./tools/getAnomalies.js";
|
|
24
|
+
import { isApiConfigured, getApiUrl, apiGet, apiPost, apiPatch, apiDelete, } from "./api/client.js";
|
|
25
|
+
import { registerSearchTools, registerCallTool, registerToolHandler, } from "./tools/catalog/index.js";
|
|
26
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
27
|
+
// Exposed Tools - Registered directly with the MCP server
|
|
28
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
21
29
|
import { registerGetDomains } from "./tools/getDomains.js";
|
|
22
|
-
import { registerGetActionableIssues } from "./tools/getActionableIssues.js";
|
|
23
|
-
import { registerGetUxHealthReport } from "./tools/getUxHealthReport.js";
|
|
24
|
-
import { registerAnalyzeFlow } from "./tools/analyzeFlow.js";
|
|
25
|
-
import { registerAnalyzeFunnel } from "./tools/analyzeFunnel.js";
|
|
26
|
-
import { registerGetFlowFriction } from "./tools/getFlowFriction.js";
|
|
27
|
-
import { registerGetJourneyPatterns } from "./tools/getJourneyPatterns.js";
|
|
28
|
-
import { registerGetDeadClicks } from "./tools/getDeadClicks.js";
|
|
29
|
-
import { registerGetConsoleErrors } from "./tools/getConsoleErrors.js";
|
|
30
|
-
import { registerCompareCohorts } from "./tools/compareCohorts.js";
|
|
31
|
-
import { registerDetectRegressions } from "./tools/detectRegressions.js";
|
|
32
|
-
import { registerDiscoverPersonas } from "./tools/discoverPersonas.js";
|
|
33
|
-
import { registerGetFormFriction } from "./tools/getFormFriction.js";
|
|
34
|
-
import { registerScanSite } from "./tools/scanSite.js";
|
|
35
|
-
import { registerListPages } from "./tools/listPages.js";
|
|
36
|
-
import { registerComparePeriods } from "./tools/comparePeriods.js";
|
|
37
|
-
import { registerDetectDrift } from "./tools/detectDrift.js";
|
|
38
|
-
import { registerPredictOutcomes } from "./tools/predictOutcomes.js";
|
|
39
30
|
import { registerMemoryTools } from "./tools/memory.js";
|
|
40
|
-
import { registerListSessions } from "./tools/listSessions.js";
|
|
41
31
|
import { registerTriageSessions } from "./tools/triageSessions.js";
|
|
42
32
|
import { registerDiagnosticTools } from "./tools/diagnostic.js";
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
33
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
34
|
+
// Hidden Tool Handlers - Registered with call_tool registry
|
|
35
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
36
|
+
function createApiHandler(method, endpoint, buildParams) {
|
|
37
|
+
return async (args) => {
|
|
38
|
+
if (!isApiConfigured()) {
|
|
39
|
+
return {
|
|
40
|
+
content: [
|
|
41
|
+
{
|
|
42
|
+
type: "text",
|
|
43
|
+
text: JSON.stringify({ error: "API not configured" }),
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
isError: true,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
const url = typeof endpoint === "function" ? endpoint(args) : endpoint;
|
|
50
|
+
const params = buildParams ? buildParams(args) : args;
|
|
51
|
+
let result;
|
|
52
|
+
switch (method) {
|
|
53
|
+
case "GET":
|
|
54
|
+
result = await apiGet(url, params);
|
|
55
|
+
break;
|
|
56
|
+
case "POST":
|
|
57
|
+
result = await apiPost(url, params);
|
|
58
|
+
break;
|
|
59
|
+
case "PATCH":
|
|
60
|
+
result = await apiPatch(url, params);
|
|
61
|
+
break;
|
|
62
|
+
case "DELETE":
|
|
63
|
+
result = await apiDelete(url);
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
if (result.error) {
|
|
67
|
+
return {
|
|
68
|
+
content: [
|
|
69
|
+
{ type: "text", text: JSON.stringify({ error: result.error }) },
|
|
70
|
+
],
|
|
71
|
+
isError: true,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return { content: [{ type: "text", text: JSON.stringify(result.data) }] };
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function registerHiddenTools() {
|
|
78
|
+
// Page Analysis
|
|
79
|
+
registerToolHandler("get_page_metrics", createApiHandler("GET", "/pages"));
|
|
80
|
+
registerToolHandler("get_element_friction", createApiHandler("GET", "/elements"));
|
|
81
|
+
registerToolHandler("get_page_trends", createApiHandler("GET", "/trends"));
|
|
82
|
+
registerToolHandler("get_dead_clicks", createApiHandler("GET", "/dead-clicks"));
|
|
83
|
+
registerToolHandler("get_console_errors", createApiHandler("GET", "/console-errors"));
|
|
84
|
+
registerToolHandler("get_form_friction", createApiHandler("GET", "/forms/friction"));
|
|
85
|
+
registerToolHandler("list_pages", createApiHandler("GET", "/pages/list"));
|
|
86
|
+
registerToolHandler("scan_site", createApiHandler("GET", "/site/overview", (args) => ({
|
|
87
|
+
top_n: args.top_n ?? 10,
|
|
88
|
+
offset: args.offset ?? 0,
|
|
89
|
+
})));
|
|
90
|
+
registerToolHandler("get_ux_health_report", createApiHandler("GET", "/health-report"));
|
|
91
|
+
// Flow Analysis
|
|
92
|
+
registerToolHandler("analyze_flow", createApiHandler("POST", "/flows/analyze"));
|
|
93
|
+
registerToolHandler("analyze_funnel", createApiHandler("POST", "/flows/funnel"));
|
|
94
|
+
registerToolHandler("get_flow_friction", createApiHandler("GET", "/flow-friction"));
|
|
95
|
+
registerToolHandler("get_journey_patterns", createApiHandler("GET", "/flows/patterns"));
|
|
96
|
+
// Issue Detection
|
|
97
|
+
registerToolHandler("get_issues", createApiHandler("GET", "/issues"));
|
|
98
|
+
registerToolHandler("get_actionable_issues", createApiHandler("GET", "/actionable-issues"));
|
|
99
|
+
registerToolHandler("get_anomalies", createApiHandler("GET", "/anomalies"));
|
|
100
|
+
registerToolHandler("detect_regressions", createApiHandler("GET", "/regressions"));
|
|
101
|
+
registerToolHandler("detect_drift", createApiHandler("GET", "/drift"));
|
|
102
|
+
// Comparison & Segmentation
|
|
103
|
+
registerToolHandler("compare_cohorts", createApiHandler("POST", "/cohorts/compare"));
|
|
104
|
+
registerToolHandler("compare_periods", createApiHandler("POST", "/pages/compare-periods"));
|
|
105
|
+
registerToolHandler("discover_personas", createApiHandler("GET", "/personas"));
|
|
106
|
+
// Session Analysis
|
|
107
|
+
registerToolHandler("search_sessions", createApiHandler("POST", "/sessions/search"));
|
|
108
|
+
registerToolHandler("list_sessions", createApiHandler("GET", "/sessions"));
|
|
109
|
+
registerToolHandler("get_session_details", async (args) => {
|
|
110
|
+
if (!isApiConfigured()) {
|
|
111
|
+
return {
|
|
112
|
+
content: [
|
|
113
|
+
{
|
|
114
|
+
type: "text",
|
|
115
|
+
text: JSON.stringify({ error: "API not configured" }),
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
isError: true,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
const { session_id, session_ids } = args;
|
|
122
|
+
if (!session_id && (!session_ids || session_ids.length === 0)) {
|
|
123
|
+
return {
|
|
124
|
+
content: [
|
|
125
|
+
{
|
|
126
|
+
type: "text",
|
|
127
|
+
text: JSON.stringify({
|
|
128
|
+
error: "Either session_id or session_ids must be provided",
|
|
129
|
+
}),
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
isError: true,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
if (session_id && !session_ids) {
|
|
136
|
+
const { data, error } = await apiGet(`/sessions/${session_id}`);
|
|
137
|
+
if (error) {
|
|
138
|
+
return {
|
|
139
|
+
content: [{ type: "text", text: JSON.stringify({ error }) }],
|
|
140
|
+
isError: true,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
144
|
+
}
|
|
145
|
+
const ids = session_ids ?? [session_id];
|
|
146
|
+
const { data, error } = await apiPost("/sessions/details", {
|
|
147
|
+
session_ids: ids,
|
|
148
|
+
});
|
|
149
|
+
if (error) {
|
|
150
|
+
return {
|
|
151
|
+
content: [{ type: "text", text: JSON.stringify({ error }) }],
|
|
152
|
+
isError: true,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
156
|
+
});
|
|
157
|
+
registerToolHandler("predict_outcomes", createApiHandler("POST", "/predict"));
|
|
158
|
+
// Diagnostic (investigate_issue and validate_issue - run_full_diagnostic is exposed)
|
|
159
|
+
registerToolHandler("investigate_issue", createApiHandler("GET", (args) => `/issues/${args.issue_id}/investigate`, (args) => ({ days: args.days ?? 7 })));
|
|
160
|
+
registerToolHandler("validate_issue", createApiHandler("POST", (args) => `/issues/${args.issue_id}/validate`, (args) => ({ lookback_days: args.lookback_days ?? 3 })));
|
|
161
|
+
// Triage
|
|
162
|
+
registerToolHandler("dismiss_issue", createApiHandler("POST", (args) => `/issues/${args.issue_id}/dismiss`, (args) => ({
|
|
163
|
+
reason: args.reason,
|
|
164
|
+
explanation: args.explanation,
|
|
165
|
+
create_knowledge: args.create_knowledge ?? true,
|
|
166
|
+
})));
|
|
167
|
+
registerToolHandler("mark_intended_behavior", createApiHandler("POST", (args) => `/issues/${args.issue_id}/mark-intended`, (args) => ({ explanation: args.explanation })));
|
|
168
|
+
registerToolHandler("get_issue_history", createApiHandler("GET", (args) => `/issues/${args.issue_id}/history`));
|
|
169
|
+
// Remediation
|
|
170
|
+
registerToolHandler("propose_fix", createApiHandler("POST", "/remediations"));
|
|
171
|
+
registerToolHandler("list_pending_fixes", createApiHandler("GET", "/remediations/pending"));
|
|
172
|
+
registerToolHandler("list_remediations", createApiHandler("GET", "/remediations"));
|
|
173
|
+
registerToolHandler("confirm_deployment", createApiHandler("PATCH", (args) => `/remediations/${args.remediation_id}/deploy`, () => ({})));
|
|
174
|
+
registerToolHandler("evaluate_fix", createApiHandler("POST", (args) => `/remediations/${args.remediation_id}/evaluate`, (args) => ({ min_hours: args.min_hours ?? 24 })));
|
|
175
|
+
registerToolHandler("get_fix_history", createApiHandler("GET", (args) => `/remediations/history/${args.issue_id}`));
|
|
176
|
+
// Knowledge
|
|
177
|
+
registerToolHandler("get_site_knowledge", createApiHandler("GET", "/knowledge"));
|
|
178
|
+
registerToolHandler("add_site_knowledge", createApiHandler("POST", "/knowledge", (args) => ({
|
|
179
|
+
...args,
|
|
180
|
+
source: "agent",
|
|
181
|
+
})));
|
|
182
|
+
registerToolHandler("delete_site_knowledge", createApiHandler("DELETE", (args) => `/knowledge/${args.knowledge_id}`));
|
|
183
|
+
registerToolHandler("get_similar_fixes", createApiHandler("GET", "/knowledge/similar-fixes"));
|
|
184
|
+
}
|
|
185
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
186
|
+
// Server Instructions
|
|
187
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
188
|
+
const SERVER_INSTRUCTIONS = `# Recapt Behavioral Intelligence
|
|
59
189
|
|
|
60
190
|
This server provides behavioral data from session recordings. Use these tools to understand user behavior, identify UX issues, and find friction points.
|
|
61
191
|
|
|
192
|
+
## Tool Discovery Pattern
|
|
193
|
+
|
|
194
|
+
You have access to 40+ analysis tools. Most are hidden to reduce context size. Use this pattern:
|
|
195
|
+
|
|
196
|
+
1. **search_tools(query)** — Describe what you need in natural language
|
|
197
|
+
2. **call_tool(tool_name, arguments)** — Execute the discovered tool
|
|
198
|
+
|
|
199
|
+
Example:
|
|
200
|
+
\`\`\`
|
|
201
|
+
search_tools({ query: "analyze user navigation between pages" })
|
|
202
|
+
→ Returns: analyze_flow, analyze_funnel, get_journey_patterns...
|
|
203
|
+
|
|
204
|
+
call_tool({ tool_name: "analyze_flow", arguments: { start_page: "/pricing", end_page: "/checkout" } })
|
|
205
|
+
→ Returns: flow analysis with paths, bottlenecks, friction scores
|
|
206
|
+
\`\`\`
|
|
207
|
+
|
|
208
|
+
## Always-Available Tools
|
|
209
|
+
|
|
210
|
+
These tools are always visible (no search needed):
|
|
211
|
+
- **get_domains** — List tracked domains (good starting point)
|
|
212
|
+
- **run_full_diagnostic** — Comprehensive site analysis with prioritized issues
|
|
213
|
+
- **triage_sessions** — Find sessions needing attention
|
|
214
|
+
- **memory_*** — Store/retrieve intermediate results
|
|
215
|
+
|
|
62
216
|
## Metric Interpretation
|
|
63
217
|
|
|
64
218
|
All behavioral scores are 0-1 where higher = more of that signal:
|
|
@@ -69,232 +223,51 @@ All behavioral scores are 0-1 where higher = more of that signal:
|
|
|
69
223
|
- **drop_off_rate** > 0.3: Major leak point in a flow
|
|
70
224
|
- **spike_ratio** > 2: Critical frustration spike, likely recent regression
|
|
71
225
|
|
|
72
|
-
## Tool Orchestration Strategies
|
|
73
|
-
|
|
74
|
-
### Starting point - understand the landscape
|
|
75
|
-
1. Use \`scan_site\` or \`list_pages\` to see all tracked pages with health grades
|
|
76
|
-
2. Use \`get_ux_health_report\` for a comprehensive overview combining metrics, issues, and anomalies
|
|
77
|
-
3. Use \`get_domains\` to see which domains are being tracked
|
|
78
|
-
|
|
79
|
-
### Diagnosing a problematic page
|
|
80
|
-
1. Start with \`get_page_metrics\` to see overall behavioral scores
|
|
81
|
-
2. If frustration high → \`get_element_friction\` to find specific problematic elements
|
|
82
|
-
3. If confusion high → \`get_dead_clicks\` to find misleading UI elements users click expecting action
|
|
83
|
-
4. Check \`get_console_errors\` for JS errors that may cause unresponsiveness
|
|
84
|
-
5. Use \`get_form_friction\` if the page has forms to find problematic fields
|
|
85
|
-
|
|
86
|
-
### Understanding user flows
|
|
87
|
-
1. \`get_journey_patterns\` for organic navigation discovery (where do users go?)
|
|
88
|
-
2. \`analyze_flow\` between specific pages to see paths, bottlenecks, and friction
|
|
89
|
-
3. \`analyze_funnel\` for conversion analysis through defined steps (cart → checkout → payment)
|
|
90
|
-
4. \`get_flow_friction\` to automatically discover high-friction flows
|
|
91
|
-
|
|
92
|
-
### Finding issues to fix
|
|
93
|
-
1. \`get_issues\` for auto-detected problems (rage clicks, dead clicks, errors)
|
|
94
|
-
2. \`get_actionable_issues\` for issues with element context
|
|
95
|
-
3. \`detect_regressions\` to find recent degradations (compare last 24h vs baseline)
|
|
96
|
-
4. \`get_anomalies\` for unusual sessions and frustration spikes
|
|
97
|
-
|
|
98
|
-
### Comparing segments
|
|
99
|
-
1. \`compare_cohorts\` to understand differences (mobile vs desktop, completed vs abandoned)
|
|
100
|
-
2. \`compare_periods\` to measure impact of changes (before vs after deployment)
|
|
101
|
-
3. \`discover_personas\` to find behavioral user segments
|
|
102
|
-
|
|
103
|
-
### Deep-diving a session
|
|
104
|
-
1. \`search_sessions\` with natural language to find relevant sessions
|
|
105
|
-
2. \`list_sessions\` to browse by domain, status, or device
|
|
106
|
-
3. \`get_session_details\` for behavioral timeline of a specific session
|
|
107
|
-
|
|
108
|
-
### Monitoring over time
|
|
109
|
-
1. \`get_page_trends\` for daily behavioral trends on a page
|
|
110
|
-
2. \`detect_drift\` for gradual behavioral changes over weeks
|
|
111
|
-
3. \`detect_regressions\` for sudden changes (deployment impact)
|
|
112
|
-
|
|
113
226
|
## Reasoning Tips
|
|
114
227
|
|
|
115
|
-
- High rage clicks on body/root elements often indicate JS errors
|
|
116
|
-
- Backtrack hotspots
|
|
117
|
-
-
|
|
118
|
-
-
|
|
119
|
-
- When frustration spikes recently, use \`detect_regressions\` to correlate with deployments
|
|
120
|
-
- Low confidence + high confusion = users don't understand what to do next
|
|
121
|
-
- High frustration + low confusion = users know what to do but can't (broken UI, errors)
|
|
228
|
+
- High rage clicks on body/root elements often indicate JS errors - search "console errors"
|
|
229
|
+
- Backtrack hotspots suggest confusion on subsequent pages
|
|
230
|
+
- Low confidence + high confusion = users don't understand what to do
|
|
231
|
+
- High frustration + low confusion = users know what to do but can't (broken UI)
|
|
122
232
|
- Use \`memory_save\` to store intermediate results when doing multi-step analysis
|
|
123
233
|
|
|
124
|
-
##
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
- \`get_actionable_issues\`: Issues with element context
|
|
149
|
-
- \`get_anomalies\`: Unusual sessions and spikes
|
|
150
|
-
- \`detect_regressions\`: Recent degradations
|
|
151
|
-
|
|
152
|
-
### Comparison & Segmentation
|
|
153
|
-
- \`compare_cohorts\`: Compare user segments
|
|
154
|
-
- \`compare_periods\`: Compare time periods
|
|
155
|
-
- \`discover_personas\`: Behavioral clustering
|
|
156
|
-
- \`detect_drift\`: Long-term behavioral changes
|
|
157
|
-
|
|
158
|
-
### Session Analysis
|
|
159
|
-
- \`search_sessions\`: Natural language session search
|
|
160
|
-
- \`list_sessions\`: Filter sessions by criteria
|
|
161
|
-
- \`get_session_details\`: Session behavioral timeline
|
|
162
|
-
- \`predict_outcomes\`: Predict session outcomes
|
|
163
|
-
- \`triage_sessions\`: Auto-triage sessions with compromised UX
|
|
164
|
-
|
|
165
|
-
### Session Triage
|
|
166
|
-
Use \`triage_sessions\` to automatically identify sessions that need attention:
|
|
167
|
-
- Surfaces sessions with user comments (direct feedback)
|
|
168
|
-
- Flags high-frustration sessions with rage clicks
|
|
169
|
-
- Includes console errors as evidence
|
|
170
|
-
- Returns replay URLs for quick investigation
|
|
171
|
-
|
|
172
|
-
Severity levels:
|
|
173
|
-
- **critical**: triage_score >= 0.7 OR has comment + high frustration
|
|
174
|
-
- **high**: triage_score >= 0.5
|
|
175
|
-
- **medium**: triage_score >= 0.3
|
|
176
|
-
- **low**: triage_score < 0.3
|
|
177
|
-
|
|
178
|
-
When triaging, prioritize:
|
|
179
|
-
1. Sessions with user comments (explicit feedback is gold)
|
|
180
|
-
2. Critical severity with rage clicks (users actively struggling)
|
|
181
|
-
3. Sessions with console errors + high frustration (likely bugs)
|
|
182
|
-
|
|
183
|
-
### Working Memory
|
|
184
|
-
- \`memory_save\`, \`memory_recall\`, \`memory_list\`, \`memory_delete\`, \`memory_clear\`: Store and retrieve intermediate results
|
|
185
|
-
|
|
186
|
-
## Self-Healing Workflow
|
|
187
|
-
|
|
188
|
-
When asked to "fix all issues", "heal the site", or "improve my site via recapt":
|
|
189
|
-
|
|
190
|
-
### 1. Full Diagnostic
|
|
191
|
-
- Call \`run_full_diagnostic\` to get prioritized issue list with severity scores
|
|
192
|
-
- Call \`get_site_knowledge\` to load known false positives and intended behaviors
|
|
193
|
-
- Review the \`recommended_investigation_order\` to prioritize your work
|
|
194
|
-
|
|
195
|
-
### 2. Triage Each Issue
|
|
196
|
-
For each issue in priority order, determine if it's actionable:
|
|
197
|
-
- Call \`validate_issue\` to check if still occurring (not stale)
|
|
198
|
-
- Check against site knowledge for known false positives
|
|
199
|
-
- If recommendation is "dismiss_stale", consider dismissing
|
|
200
|
-
- If uncertain, call \`investigate_issue\` for deep context
|
|
201
|
-
- **Always ask user to confirm** if behavior is intended when unclear
|
|
202
|
-
|
|
203
|
-
### 3. Propose Fixes
|
|
204
|
-
For confirmed issues:
|
|
205
|
-
- Analyze root cause from evidence and element context
|
|
206
|
-
- Call \`get_similar_fixes\` to see what worked before for similar issues
|
|
207
|
-
- Call \`get_fix_history\` to see past attempts on this specific issue
|
|
208
|
-
- Call \`propose_fix\` with detailed diagnosis and code suggestion
|
|
209
|
-
- Explain confidence level and reasoning to user
|
|
210
|
-
- **Ask for confirmation when confidence < 0.7**
|
|
211
|
-
|
|
212
|
-
### 4. Track Deployments
|
|
213
|
-
- Show user all pending fixes with \`list_pending_fixes\`
|
|
214
|
-
- When user confirms "I have deployed this fix", call \`confirm_deployment\`
|
|
215
|
-
- Explain that evaluation will happen after 24-48 hours of data collection
|
|
216
|
-
|
|
217
|
-
### 5. Evaluate Results
|
|
218
|
-
- After deployment window (24-48h), call \`evaluate_fix\`
|
|
219
|
-
- If outcome is "success": celebrate, the issue will be auto-resolved
|
|
220
|
-
- If outcome is "partial": discuss with user whether to iterate
|
|
221
|
-
- If outcome is "failed": analyze why, propose alternative approach
|
|
222
|
-
- Store learnings with \`add_site_knowledge\` for future reference
|
|
223
|
-
|
|
224
|
-
### Evaluation Thresholds
|
|
225
|
-
- **Success**: frustration decreased >15% OR health score increased >10 points
|
|
226
|
-
- **Partial**: frustration decreased 5-15% OR health score increased 3-10 points
|
|
227
|
-
- **Failed**: no improvement or regression
|
|
228
|
-
|
|
229
|
-
### Asking for Confirmation
|
|
230
|
-
Always ask user before:
|
|
231
|
-
- Dismissing an issue as false positive
|
|
232
|
-
- Marking behavior as intended
|
|
233
|
-
- When confidence in fix is <0.7
|
|
234
|
-
- Before evaluating (ensure they've actually deployed)
|
|
235
|
-
|
|
236
|
-
### Self-Healing Tools
|
|
237
|
-
|
|
238
|
-
#### Diagnostic
|
|
239
|
-
- \`run_full_diagnostic\`: Comprehensive site analysis with prioritized issues
|
|
240
|
-
- \`investigate_issue\`: Deep-dive into specific issue with sessions and errors
|
|
241
|
-
- \`validate_issue\`: Check if issue is still occurring (not stale)
|
|
242
|
-
|
|
243
|
-
#### Triage
|
|
244
|
-
- \`dismiss_issue\`: Mark issue as false positive with reason
|
|
245
|
-
- \`mark_intended_behavior\`: Flag behavior as by design
|
|
246
|
-
- \`get_issue_history\`: View past occurrences and fix attempts
|
|
247
|
-
|
|
248
|
-
#### Remediation
|
|
249
|
-
- \`propose_fix\`: Create remediation record with baseline metrics
|
|
250
|
-
- \`list_pending_fixes\`: Show fixes awaiting deployment
|
|
251
|
-
- \`list_remediations\`: Browse all remediation records
|
|
252
|
-
- \`confirm_deployment\`: Mark fix as deployed, start evaluation timer
|
|
253
|
-
- \`evaluate_fix\`: Compare post-deploy metrics to baseline
|
|
254
|
-
- \`get_fix_history\`: View all fix attempts for an issue
|
|
255
|
-
|
|
256
|
-
#### Knowledge
|
|
257
|
-
- \`get_site_knowledge\`: Retrieve learned patterns and false positives
|
|
258
|
-
- \`add_site_knowledge\`: Store new learning for future reference
|
|
259
|
-
- \`delete_site_knowledge\`: Remove outdated knowledge
|
|
260
|
-
- \`get_similar_fixes\`: Find past fixes for similar issues`,
|
|
234
|
+
## Installable Skills
|
|
235
|
+
|
|
236
|
+
For guided workflows (self-healing, deep-dive analysis, regression hunting), install recapt skills:
|
|
237
|
+
\`\`\`bash
|
|
238
|
+
npx @recapt/mcp skill list
|
|
239
|
+
npx @recapt/mcp skill install self-healing
|
|
240
|
+
\`\`\`
|
|
241
|
+
Skills provide step-by-step guidance for complex multi-tool workflows.`;
|
|
242
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
243
|
+
// Main
|
|
244
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
245
|
+
async function main() {
|
|
246
|
+
console.error("[MCP] Starting recapt behavioral intelligence server...");
|
|
247
|
+
if (!isApiConfigured()) {
|
|
248
|
+
console.error("[MCP] ERROR: RECAPT_SECRET_KEY environment variable is required");
|
|
249
|
+
process.exit(1);
|
|
250
|
+
}
|
|
251
|
+
console.error(`[MCP] API URL: ${getApiUrl()}`);
|
|
252
|
+
const server = new McpServer({
|
|
253
|
+
name: "recapt",
|
|
254
|
+
version: "1.0.0",
|
|
255
|
+
}, {
|
|
256
|
+
capabilities: { logging: {} },
|
|
257
|
+
instructions: SERVER_INSTRUCTIONS,
|
|
261
258
|
});
|
|
259
|
+
// Register hidden tool handlers first (for call_tool to use)
|
|
260
|
+
registerHiddenTools();
|
|
261
|
+
// Register exposed tools
|
|
262
|
+
registerSearchTools(server);
|
|
263
|
+
registerCallTool(server);
|
|
262
264
|
registerGetDomains(server);
|
|
263
|
-
|
|
264
|
-
registerGetElementFriction(server);
|
|
265
|
-
registerSearchSessions(server);
|
|
266
|
-
registerGetIssues(server);
|
|
267
|
-
registerGetSessionDetails(server);
|
|
268
|
-
registerGetPageTrends(server);
|
|
269
|
-
registerGetAnomalies(server);
|
|
270
|
-
registerGetActionableIssues(server);
|
|
271
|
-
registerGetUxHealthReport(server);
|
|
272
|
-
registerAnalyzeFlow(server);
|
|
273
|
-
registerAnalyzeFunnel(server);
|
|
274
|
-
registerGetFlowFriction(server);
|
|
275
|
-
registerGetJourneyPatterns(server);
|
|
276
|
-
registerGetDeadClicks(server);
|
|
277
|
-
registerGetConsoleErrors(server);
|
|
278
|
-
registerCompareCohorts(server);
|
|
279
|
-
registerDetectRegressions(server);
|
|
280
|
-
registerDiscoverPersonas(server);
|
|
281
|
-
registerGetFormFriction(server);
|
|
282
|
-
registerScanSite(server);
|
|
283
|
-
registerListPages(server);
|
|
284
|
-
registerComparePeriods(server);
|
|
285
|
-
registerDetectDrift(server);
|
|
286
|
-
registerPredictOutcomes(server);
|
|
287
|
-
registerMemoryTools(server);
|
|
288
|
-
registerListSessions(server);
|
|
265
|
+
registerDiagnosticTools(server); // Includes run_full_diagnostic
|
|
289
266
|
registerTriageSessions(server);
|
|
290
|
-
|
|
291
|
-
registerDiagnosticTools(server);
|
|
292
|
-
registerTriageTools(server);
|
|
293
|
-
registerRemediationTools(server);
|
|
294
|
-
registerKnowledgeTools(server);
|
|
267
|
+
registerMemoryTools(server);
|
|
295
268
|
const transport = new StdioServerTransport();
|
|
296
269
|
await server.connect(transport);
|
|
297
|
-
console.error("[MCP] Server running on stdio");
|
|
270
|
+
console.error("[MCP] Server running on stdio (10 exposed tools, 38 hidden)");
|
|
298
271
|
}
|
|
299
272
|
main().catch((err) => {
|
|
300
273
|
console.error("[MCP] Fatal error:", err);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Call Tool — Universal tool proxy for executing any tool by name.
|
|
3
|
+
*
|
|
4
|
+
* This tool allows the agent to invoke ANY tool by name without having
|
|
5
|
+
* all tool descriptions in context. The agent discovers tools via search_tools,
|
|
6
|
+
* then calls them through this proxy.
|
|
7
|
+
*
|
|
8
|
+
* Benefits:
|
|
9
|
+
* - Minimal context: Only ~10 tools have descriptions in the prompt
|
|
10
|
+
* - All 40+ analysis tools accessible on-demand
|
|
11
|
+
* - Scales to any number of tools without context bloat
|
|
12
|
+
*/
|
|
13
|
+
export type ToolHandler = (args: Record<string, unknown>) => Promise<{
|
|
14
|
+
content: Array<{
|
|
15
|
+
type: string;
|
|
16
|
+
text: string;
|
|
17
|
+
}>;
|
|
18
|
+
isError?: boolean;
|
|
19
|
+
}>;
|
|
20
|
+
export declare function registerToolHandler(name: string, handler: ToolHandler): void;
|
|
21
|
+
export declare function getToolHandler(name: string): ToolHandler | undefined;
|
|
22
|
+
export declare function registerCallTool(server: any): void;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Call Tool — Universal tool proxy for executing any tool by name.
|
|
3
|
+
*
|
|
4
|
+
* This tool allows the agent to invoke ANY tool by name without having
|
|
5
|
+
* all tool descriptions in context. The agent discovers tools via search_tools,
|
|
6
|
+
* then calls them through this proxy.
|
|
7
|
+
*
|
|
8
|
+
* Benefits:
|
|
9
|
+
* - Minimal context: Only ~10 tools have descriptions in the prompt
|
|
10
|
+
* - All 40+ analysis tools accessible on-demand
|
|
11
|
+
* - Scales to any number of tools without context bloat
|
|
12
|
+
*/
|
|
13
|
+
import { z } from "zod";
|
|
14
|
+
import { getToolByName } from "./searchTools.js";
|
|
15
|
+
const toolRegistry = new Map();
|
|
16
|
+
export function registerToolHandler(name, handler) {
|
|
17
|
+
toolRegistry.set(name, handler);
|
|
18
|
+
}
|
|
19
|
+
export function getToolHandler(name) {
|
|
20
|
+
return toolRegistry.get(name);
|
|
21
|
+
}
|
|
22
|
+
const callToolSchema = z.object({
|
|
23
|
+
tool_name: z
|
|
24
|
+
.string()
|
|
25
|
+
.describe("The exact name of the tool to call (e.g., 'get_page_metrics', 'analyze_flow', 'compare_cohorts')"),
|
|
26
|
+
arguments: z
|
|
27
|
+
.record(z.string(), z.unknown())
|
|
28
|
+
.describe("The arguments to pass to the tool as a JSON object. Check the tool description from search_tools for required parameters."),
|
|
29
|
+
});
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
31
|
+
export function registerCallTool(server) {
|
|
32
|
+
server.registerTool("call_tool", {
|
|
33
|
+
description: "Execute any analysis tool by name. Use search_tools first to discover available tools, " +
|
|
34
|
+
"then call them through this proxy. Pass the exact tool name and arguments as a JSON object. " +
|
|
35
|
+
"Example: call_tool({ tool_name: 'get_page_metrics', arguments: { page_path: '/checkout' } })",
|
|
36
|
+
inputSchema: callToolSchema,
|
|
37
|
+
}, async ({ tool_name, arguments: args }) => {
|
|
38
|
+
const handler = toolRegistry.get(tool_name);
|
|
39
|
+
if (!handler) {
|
|
40
|
+
const catalogEntry = getToolByName(tool_name);
|
|
41
|
+
if (catalogEntry) {
|
|
42
|
+
return {
|
|
43
|
+
content: [
|
|
44
|
+
{
|
|
45
|
+
type: "text",
|
|
46
|
+
text: JSON.stringify({
|
|
47
|
+
error: `Tool "${tool_name}" exists in catalog but is not registered. This may be a server configuration issue.`,
|
|
48
|
+
tool_info: {
|
|
49
|
+
name: catalogEntry.name,
|
|
50
|
+
description: catalogEntry.description,
|
|
51
|
+
category: catalogEntry.category,
|
|
52
|
+
},
|
|
53
|
+
}),
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
isError: true,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
content: [
|
|
61
|
+
{
|
|
62
|
+
type: "text",
|
|
63
|
+
text: JSON.stringify({
|
|
64
|
+
error: `Unknown tool: ${tool_name}`,
|
|
65
|
+
hint: "Use search_tools to discover available tools first.",
|
|
66
|
+
}),
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
isError: true,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
return await handler(args);
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
77
|
+
return {
|
|
78
|
+
content: [
|
|
79
|
+
{
|
|
80
|
+
type: "text",
|
|
81
|
+
text: JSON.stringify({
|
|
82
|
+
error: `Tool execution failed: ${message}`,
|
|
83
|
+
tool_name,
|
|
84
|
+
arguments: args,
|
|
85
|
+
}),
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
isError: true,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Catalog — Registry and discovery for MCP tools.
|
|
3
|
+
*
|
|
4
|
+
* Exports:
|
|
5
|
+
* - searchTools: Find tools by natural language query
|
|
6
|
+
* - registerSearchTools: Register the search_tools MCP tool
|
|
7
|
+
* - registerCallTool: Register the call_tool MCP tool
|
|
8
|
+
* - registerToolHandler: Register a tool handler for call_tool to invoke
|
|
9
|
+
*/
|
|
10
|
+
export { searchTools, getToolByName, getAllTools, registerSearchTools, type ToolEntry, } from "./searchTools.js";
|
|
11
|
+
export { registerCallTool, registerToolHandler, getToolHandler, type ToolHandler, } from "./callTool.js";
|