@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/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
- * 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
32
  import { registerDiagnosticTools } from "./tools/diagnostic.js";
43
- import { registerTriageTools } from "./tools/triage.js";
44
- import { registerRemediationTools } from "./tools/remediation.js";
45
- import { registerKnowledgeTools } from "./tools/knowledge.js";
46
- async function main() {
47
- console.error("[MCP] Starting recapt behavioral intelligence server...");
48
- if (!isApiConfigured()) {
49
- console.error("[MCP] ERROR: RECAPT_SECRET_KEY environment variable is required");
50
- process.exit(1);
51
- }
52
- console.error(`[MCP] API URL: ${getApiUrl()}`);
53
- const server = new McpServer({
54
- name: "recapt",
55
- version: "1.0.0",
56
- }, {
57
- capabilities: { logging: {} },
58
- instructions: `# Recapt Behavioral Intelligence
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 preventing interaction - check \`get_console_errors\`
116
- - Backtrack hotspots (pages users return to repeatedly) suggest confusion or errors on subsequent pages
117
- - Drop-off pages may be intentional exits (thank you page) or problems - check if it's a terminal page
118
- - Compare frustration across device types with \`compare_cohorts\` - mobile often has different issues
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
- ## Available Tools
125
-
126
- ### Site Overview
127
- - \`get_domains\`: List configured domains
128
- - \`scan_site\`: Quick health scan of top pages
129
- - \`list_pages\`: List all tracked pages with metrics
130
- - \`get_ux_health_report\`: Comprehensive health report
131
-
132
- ### Page Analysis
133
- - \`get_page_metrics\`: Behavioral metrics for a page
134
- - \`get_element_friction\`: Per-element friction data
135
- - \`get_page_trends\`: Daily trends over time
136
- - \`get_dead_clicks\`: Unresponsive elements users click
137
- - \`get_console_errors\`: JavaScript errors
138
- - \`get_form_friction\`: Form field friction analysis
139
-
140
- ### Flow Analysis
141
- - \`analyze_flow\`: Navigation between specific pages
142
- - \`analyze_funnel\`: Conversion through page sequence
143
- - \`get_flow_friction\`: Discover high-friction flows
144
- - \`get_journey_patterns\`: Navigation patterns and hotspots
145
-
146
- ### Issue Detection
147
- - \`get_issues\`: Auto-detected UX issues
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
- registerGetPageMetrics(server);
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
- // Self-healing tools
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";