@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.
@@ -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: Record<string, unknown>): Promise<ApiResponse<T>>;
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 {};
@@ -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 || "http://localhost:4000";
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
- * Acts as a thin proxy to external-api query endpoints.
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
- * Acts as a thin proxy to external-api query endpoints.
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 { registerGetPageMetrics } from "./tools/getPageMetrics.js";
15
- import { registerGetElementFriction } from "./tools/getElementFriction.js";
16
- import { registerSearchSessions } from "./tools/searchSessions.js";
17
- import { registerGetIssues } from "./tools/getIssues.js";
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
- async function main() {
43
- console.error("[MCP] Starting recapt behavioral intelligence server...");
44
- if (!isApiConfigured()) {
45
- console.error("[MCP] ERROR: RECAPT_SECRET_KEY environment variable is required");
46
- process.exit(1);
47
- }
48
- console.error(`[MCP] API URL: ${getApiUrl()}`);
49
- const server = new McpServer({
50
- name: "recapt",
51
- version: "1.0.0",
52
- }, {
53
- capabilities: { logging: {} },
54
- instructions: `# Recapt Behavioral Intelligence
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
- ## Tool Orchestration Strategies
226
+ ## Common Workflows
69
227
 
70
228
  ### Starting point - understand the landscape
71
- 1. Use \`scan_site\` or \`list_pages\` to see all tracked pages with health grades
72
- 2. Use \`get_ux_health_report\` for a comprehensive overview combining metrics, issues, and anomalies
73
- 3. Use \`get_domains\` to see which domains are being tracked
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
- 1. Start with \`get_page_metrics\` to see overall behavioral scores
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
- 1. \`get_journey_patterns\` for organic navigation discovery (where do users go?)
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. \`get_issues\` for auto-detected problems (rage clicks, dead clicks, errors)
90
- 2. \`get_actionable_issues\` for issues with element context
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
- 1. \`compare_cohorts\` to understand differences (mobile vs desktop, completed vs abandoned)
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
- 1. \`search_sessions\` with natural language to find relevant sessions
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 preventing interaction - check \`get_console_errors\`
112
- - Backtrack hotspots (pages users return to repeatedly) suggest confusion or errors on subsequent pages
113
- - Drop-off pages may be intentional exits (thank you page) or problems - check if it's a terminal page
114
- - Compare frustration across device types with \`compare_cohorts\` - mobile often has different issues
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
- ## Available Tools
121
-
122
- ### Site Overview
123
- - \`get_domains\`: List configured domains
124
- - \`scan_site\`: Quick health scan of top pages
125
- - \`list_pages\`: List all tracked pages with metrics
126
- - \`get_ux_health_report\`: Comprehensive health report
127
-
128
- ### Page Analysis
129
- - \`get_page_metrics\`: Behavioral metrics for a page
130
- - \`get_element_friction\`: Per-element friction data
131
- - \`get_page_trends\`: Daily trends over time
132
- - \`get_dead_clicks\`: Unresponsive elements users click
133
- - \`get_console_errors\`: JavaScript errors
134
- - \`get_form_friction\`: Form field friction analysis
135
-
136
- ### Flow Analysis
137
- - \`analyze_flow\`: Navigation between specific pages
138
- - \`analyze_funnel\`: Conversion through page sequence
139
- - \`get_flow_friction\`: Discover high-friction flows
140
- - \`get_journey_patterns\`: Navigation patterns and hotspots
141
-
142
- ### Issue Detection
143
- - \`get_issues\`: Auto-detected UX issues
144
- - \`get_actionable_issues\`: Issues with element context
145
- - \`get_anomalies\`: Unusual sessions and spikes
146
- - \`detect_regressions\`: Recent degradations
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
- registerGetPageMetrics(server);
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;