@recapt/mcp 0.0.3-beta → 0.0.5-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.d.ts +3 -1
- package/dist/api/client.js +51 -2
- package/dist/index.d.ts +12 -1
- package/dist/index.js +247 -163
- 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 +149 -0
- package/dist/tools/diagnostic.d.ts +6 -0
- package/dist/tools/diagnostic.js +102 -0
- package/dist/tools/knowledge.d.ts +6 -0
- package/dist/tools/knowledge.js +186 -0
- package/dist/tools/remediation.d.ts +6 -0
- package/dist/tools/remediation.js +223 -0
- package/dist/tools/triage.d.ts +6 -0
- package/dist/tools/triage.js +114 -0
- package/package.json +6 -2
package/dist/api/client.d.ts
CHANGED
|
@@ -8,5 +8,7 @@ interface ApiResponse<T> {
|
|
|
8
8
|
error?: string;
|
|
9
9
|
}
|
|
10
10
|
export declare function apiGet<T>(path: string, params?: Record<string, string | number | undefined>): Promise<ApiResponse<T>>;
|
|
11
|
-
export declare function apiPost<T>(path: string, body
|
|
11
|
+
export declare function apiPost<T>(path: string, body?: Record<string, unknown>): Promise<ApiResponse<T>>;
|
|
12
|
+
export declare function apiPatch<T>(path: string, body?: Record<string, unknown>): Promise<ApiResponse<T>>;
|
|
13
|
+
export declare function apiDelete<T>(path: string): Promise<ApiResponse<T>>;
|
|
12
14
|
export {};
|
package/dist/api/client.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* HTTP client for calling external-api query endpoints.
|
|
3
3
|
*/
|
|
4
|
-
const API_URL = process.env.EXTERNAL_API_URL || "
|
|
4
|
+
const API_URL = process.env.EXTERNAL_API_URL || "https://api.recapt.app";
|
|
5
5
|
const SECRET_KEY = process.env.RECAPT_SECRET_KEY;
|
|
6
6
|
export function isApiConfigured() {
|
|
7
7
|
return !!SECRET_KEY;
|
|
@@ -40,7 +40,7 @@ export async function apiGet(path, params) {
|
|
|
40
40
|
return { error: err instanceof Error ? err.message : String(err) };
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
-
export async function apiPost(path, body) {
|
|
43
|
+
export async function apiPost(path, body = {}) {
|
|
44
44
|
if (!SECRET_KEY) {
|
|
45
45
|
return { error: "RECAPT_SECRET_KEY not configured" };
|
|
46
46
|
}
|
|
@@ -65,3 +65,52 @@ export async function apiPost(path, body) {
|
|
|
65
65
|
return { error: err instanceof Error ? err.message : String(err) };
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
|
+
export async function apiPatch(path, body = {}) {
|
|
69
|
+
if (!SECRET_KEY) {
|
|
70
|
+
return { error: "RECAPT_SECRET_KEY not configured" };
|
|
71
|
+
}
|
|
72
|
+
const url = `${API_URL}/v1beta/query${path}`;
|
|
73
|
+
try {
|
|
74
|
+
const res = await fetch(url, {
|
|
75
|
+
method: "PATCH",
|
|
76
|
+
headers: {
|
|
77
|
+
"x-private-key": SECRET_KEY,
|
|
78
|
+
"Content-Type": "application/json",
|
|
79
|
+
},
|
|
80
|
+
body: JSON.stringify(body),
|
|
81
|
+
});
|
|
82
|
+
if (!res.ok) {
|
|
83
|
+
const responseData = (await res.json().catch(() => ({})));
|
|
84
|
+
return { error: responseData.error || `HTTP ${res.status}` };
|
|
85
|
+
}
|
|
86
|
+
const data = (await res.json());
|
|
87
|
+
return { data };
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
return { error: err instanceof Error ? err.message : String(err) };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
export async function apiDelete(path) {
|
|
94
|
+
if (!SECRET_KEY) {
|
|
95
|
+
return { error: "RECAPT_SECRET_KEY not configured" };
|
|
96
|
+
}
|
|
97
|
+
const url = `${API_URL}/v1beta/query${path}`;
|
|
98
|
+
try {
|
|
99
|
+
const res = await fetch(url, {
|
|
100
|
+
method: "DELETE",
|
|
101
|
+
headers: {
|
|
102
|
+
"x-private-key": SECRET_KEY,
|
|
103
|
+
"Content-Type": "application/json",
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
if (!res.ok) {
|
|
107
|
+
const responseData = (await res.json().catch(() => ({})));
|
|
108
|
+
return { error: responseData.error || `HTTP ${res.status}` };
|
|
109
|
+
}
|
|
110
|
+
const data = (await res.json());
|
|
111
|
+
return { data };
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
return { error: err instanceof Error ? err.message : String(err) };
|
|
115
|
+
}
|
|
116
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
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";
|
package/dist/index.js
CHANGED
|
@@ -3,58 +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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
32
|
+
import { registerDiagnosticTools } from "./tools/diagnostic.js";
|
|
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
|
|
55
189
|
|
|
56
190
|
This server provides behavioral data from session recordings. Use these tools to understand user behavior, identify UX issues, and find friction points.
|
|
57
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
|
+
|
|
58
216
|
## Metric Interpretation
|
|
59
217
|
|
|
60
218
|
All behavioral scores are 0-1 where higher = more of that signal:
|
|
@@ -65,151 +223,77 @@ All behavioral scores are 0-1 where higher = more of that signal:
|
|
|
65
223
|
- **drop_off_rate** > 0.3: Major leak point in a flow
|
|
66
224
|
- **spike_ratio** > 2: Critical frustration spike, likely recent regression
|
|
67
225
|
|
|
68
|
-
##
|
|
226
|
+
## Common Workflows
|
|
69
227
|
|
|
70
228
|
### Starting point - understand the landscape
|
|
71
|
-
1.
|
|
72
|
-
2.
|
|
73
|
-
3.
|
|
229
|
+
1. \`get_domains\` to see tracked domains
|
|
230
|
+
2. \`run_full_diagnostic\` for comprehensive overview
|
|
231
|
+
3. Or search: "site overview" → scan_site, list_pages, get_ux_health_report
|
|
74
232
|
|
|
75
233
|
### Diagnosing a problematic page
|
|
76
|
-
|
|
77
|
-
2. If frustration high → \`get_element_friction\` to find specific problematic elements
|
|
78
|
-
3. If confusion high → \`get_dead_clicks\` to find misleading UI elements users click expecting action
|
|
79
|
-
4. Check \`get_console_errors\` for JS errors that may cause unresponsiveness
|
|
80
|
-
5. Use \`get_form_friction\` if the page has forms to find problematic fields
|
|
234
|
+
Search: "page analysis" or "element friction" → get_page_metrics, get_element_friction, get_dead_clicks, get_console_errors, get_form_friction
|
|
81
235
|
|
|
82
236
|
### Understanding user flows
|
|
83
|
-
|
|
84
|
-
2. \`analyze_flow\` between specific pages to see paths, bottlenecks, and friction
|
|
85
|
-
3. \`analyze_funnel\` for conversion analysis through defined steps (cart → checkout → payment)
|
|
86
|
-
4. \`get_flow_friction\` to automatically discover high-friction flows
|
|
237
|
+
Search: "user navigation" or "funnel" → analyze_flow, analyze_funnel, get_journey_patterns, get_flow_friction
|
|
87
238
|
|
|
88
239
|
### Finding issues to fix
|
|
89
|
-
1. \`
|
|
90
|
-
2.
|
|
91
|
-
3. \`detect_regressions\` to find recent degradations (compare last 24h vs baseline)
|
|
92
|
-
4. \`get_anomalies\` for unusual sessions and frustration spikes
|
|
240
|
+
1. \`run_full_diagnostic\` (always available)
|
|
241
|
+
2. Or search: "issues" → get_issues, get_actionable_issues, get_anomalies, detect_regressions
|
|
93
242
|
|
|
94
243
|
### Comparing segments
|
|
95
|
-
|
|
96
|
-
2. \`compare_periods\` to measure impact of changes (before vs after deployment)
|
|
97
|
-
3. \`discover_personas\` to find behavioral user segments
|
|
244
|
+
Search: "compare users" or "cohorts" → compare_cohorts, compare_periods, discover_personas
|
|
98
245
|
|
|
99
246
|
### Deep-diving a session
|
|
100
|
-
|
|
101
|
-
2. \`list_sessions\` to browse by domain, status, or device
|
|
102
|
-
3. \`get_session_details\` for behavioral timeline of a specific session
|
|
103
|
-
|
|
104
|
-
### Monitoring over time
|
|
105
|
-
1. \`get_page_trends\` for daily behavioral trends on a page
|
|
106
|
-
2. \`detect_drift\` for gradual behavioral changes over weeks
|
|
107
|
-
3. \`detect_regressions\` for sudden changes (deployment impact)
|
|
247
|
+
Search: "session details" → search_sessions, list_sessions, get_session_details, predict_outcomes
|
|
108
248
|
|
|
109
249
|
## Reasoning Tips
|
|
110
250
|
|
|
111
|
-
- High rage clicks on body/root elements often indicate JS errors
|
|
112
|
-
- Backtrack hotspots
|
|
113
|
-
-
|
|
114
|
-
-
|
|
115
|
-
- When frustration spikes recently, use \`detect_regressions\` to correlate with deployments
|
|
116
|
-
- Low confidence + high confusion = users don't understand what to do next
|
|
117
|
-
- High frustration + low confusion = users know what to do but can't (broken UI, errors)
|
|
251
|
+
- High rage clicks on body/root elements often indicate JS errors - search "console errors"
|
|
252
|
+
- Backtrack hotspots suggest confusion on subsequent pages
|
|
253
|
+
- Low confidence + high confusion = users don't understand what to do
|
|
254
|
+
- High frustration + low confusion = users know what to do but can't (broken UI)
|
|
118
255
|
- Use \`memory_save\` to store intermediate results when doing multi-step analysis
|
|
119
256
|
|
|
120
|
-
##
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
-
### Comparison & Segmentation
|
|
149
|
-
- \`compare_cohorts\`: Compare user segments
|
|
150
|
-
- \`compare_periods\`: Compare time periods
|
|
151
|
-
- \`discover_personas\`: Behavioral clustering
|
|
152
|
-
- \`detect_drift\`: Long-term behavioral changes
|
|
153
|
-
|
|
154
|
-
### Session Analysis
|
|
155
|
-
- \`search_sessions\`: Natural language session search
|
|
156
|
-
- \`list_sessions\`: Filter sessions by criteria
|
|
157
|
-
- \`get_session_details\`: Session behavioral timeline
|
|
158
|
-
- \`predict_outcomes\`: Predict session outcomes
|
|
159
|
-
- \`triage_sessions\`: Auto-triage sessions with compromised UX
|
|
160
|
-
|
|
161
|
-
### Session Triage
|
|
162
|
-
Use \`triage_sessions\` to automatically identify sessions that need attention:
|
|
163
|
-
- Surfaces sessions with user comments (direct feedback)
|
|
164
|
-
- Flags high-frustration sessions with rage clicks
|
|
165
|
-
- Includes console errors as evidence
|
|
166
|
-
- Returns replay URLs for quick investigation
|
|
167
|
-
|
|
168
|
-
Severity levels:
|
|
169
|
-
- **critical**: triage_score >= 0.7 OR has comment + high frustration
|
|
170
|
-
- **high**: triage_score >= 0.5
|
|
171
|
-
- **medium**: triage_score >= 0.3
|
|
172
|
-
- **low**: triage_score < 0.3
|
|
173
|
-
|
|
174
|
-
When triaging, prioritize:
|
|
175
|
-
1. Sessions with user comments (explicit feedback is gold)
|
|
176
|
-
2. Critical severity with rage clicks (users actively struggling)
|
|
177
|
-
3. Sessions with console errors + high frustration (likely bugs)
|
|
178
|
-
|
|
179
|
-
### Working Memory
|
|
180
|
-
- \`memory_save\`, \`memory_recall\`, \`memory_list\`, \`memory_delete\`, \`memory_clear\`: Store and retrieve intermediate results`,
|
|
257
|
+
## Self-Healing Workflow
|
|
258
|
+
|
|
259
|
+
When asked to "fix all issues" or "heal the site":
|
|
260
|
+
|
|
261
|
+
1. **Diagnose**: \`run_full_diagnostic\` (always available)
|
|
262
|
+
2. **Investigate**: search "investigate issue" → investigate_issue, validate_issue
|
|
263
|
+
3. **Triage**: search "dismiss issue" → dismiss_issue, mark_intended_behavior
|
|
264
|
+
(you should wait here for user input, recommend continuing the workflow if the user is happy)
|
|
265
|
+
4. **Fix**: search "propose fix" → propose_fix, get_similar_fixes, get_fix_history
|
|
266
|
+
5. **Track**: search "deployment" → confirm_deployment, evaluate_fix, list_pending_fixes
|
|
267
|
+
6. **Learn**: search "site knowledge" → get_site_knowledge, add_site_knowledge`;
|
|
268
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
269
|
+
// Main
|
|
270
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
271
|
+
async function main() {
|
|
272
|
+
console.error("[MCP] Starting recapt behavioral intelligence server...");
|
|
273
|
+
if (!isApiConfigured()) {
|
|
274
|
+
console.error("[MCP] ERROR: RECAPT_SECRET_KEY environment variable is required");
|
|
275
|
+
process.exit(1);
|
|
276
|
+
}
|
|
277
|
+
console.error(`[MCP] API URL: ${getApiUrl()}`);
|
|
278
|
+
const server = new McpServer({
|
|
279
|
+
name: "recapt",
|
|
280
|
+
version: "1.0.0",
|
|
281
|
+
}, {
|
|
282
|
+
capabilities: { logging: {} },
|
|
283
|
+
instructions: SERVER_INSTRUCTIONS,
|
|
181
284
|
});
|
|
285
|
+
// Register hidden tool handlers first (for call_tool to use)
|
|
286
|
+
registerHiddenTools();
|
|
287
|
+
// Register exposed tools
|
|
288
|
+
registerSearchTools(server);
|
|
289
|
+
registerCallTool(server);
|
|
182
290
|
registerGetDomains(server);
|
|
183
|
-
|
|
184
|
-
registerGetElementFriction(server);
|
|
185
|
-
registerSearchSessions(server);
|
|
186
|
-
registerGetIssues(server);
|
|
187
|
-
registerGetSessionDetails(server);
|
|
188
|
-
registerGetPageTrends(server);
|
|
189
|
-
registerGetAnomalies(server);
|
|
190
|
-
registerGetActionableIssues(server);
|
|
191
|
-
registerGetUxHealthReport(server);
|
|
192
|
-
registerAnalyzeFlow(server);
|
|
193
|
-
registerAnalyzeFunnel(server);
|
|
194
|
-
registerGetFlowFriction(server);
|
|
195
|
-
registerGetJourneyPatterns(server);
|
|
196
|
-
registerGetDeadClicks(server);
|
|
197
|
-
registerGetConsoleErrors(server);
|
|
198
|
-
registerCompareCohorts(server);
|
|
199
|
-
registerDetectRegressions(server);
|
|
200
|
-
registerDiscoverPersonas(server);
|
|
201
|
-
registerGetFormFriction(server);
|
|
202
|
-
registerScanSite(server);
|
|
203
|
-
registerListPages(server);
|
|
204
|
-
registerComparePeriods(server);
|
|
205
|
-
registerDetectDrift(server);
|
|
206
|
-
registerPredictOutcomes(server);
|
|
207
|
-
registerMemoryTools(server);
|
|
208
|
-
registerListSessions(server);
|
|
291
|
+
registerDiagnosticTools(server); // Includes run_full_diagnostic
|
|
209
292
|
registerTriageSessions(server);
|
|
293
|
+
registerMemoryTools(server);
|
|
210
294
|
const transport = new StdioServerTransport();
|
|
211
295
|
await server.connect(transport);
|
|
212
|
-
console.error("[MCP] Server running on stdio");
|
|
296
|
+
console.error("[MCP] Server running on stdio (10 exposed tools, 38 hidden)");
|
|
213
297
|
}
|
|
214
298
|
main().catch((err) => {
|
|
215
299
|
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;
|