@recapt/mcp 0.0.17-beta → 0.0.19-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,14 +1,6 @@
1
1
  /**
2
2
  * HTTP client for calling external-api query endpoints.
3
+ *
4
+ * Re-exports from @glimt/mcp-tools for backward compatibility.
3
5
  */
4
- export declare function isApiConfigured(): boolean;
5
- export declare function getApiUrl(): string;
6
- interface ApiResponse<T> {
7
- data?: T;
8
- error?: string;
9
- }
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>>;
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>>;
14
- export {};
6
+ export { isApiConfigured, getApiUrl, apiGet, apiPost, apiPatch, apiDelete, } from "@glimt/mcp-tools";
@@ -1,67 +1,6 @@
1
1
  /**
2
2
  * HTTP client for calling external-api query endpoints.
3
+ *
4
+ * Re-exports from @glimt/mcp-tools for backward compatibility.
3
5
  */
4
- const API_URL = process.env.RECAPT_API_URL ||
5
- process.env.EXTERNAL_API_URL ||
6
- "https://api.recapt.app";
7
- const SECRET_KEY = process.env.RECAPT_SECRET_KEY;
8
- const REQUEST_TIMEOUT_MS = 120_000;
9
- export function isApiConfigured() {
10
- return !!SECRET_KEY;
11
- }
12
- export function getApiUrl() {
13
- return API_URL;
14
- }
15
- async function request(options) {
16
- const { method, path, params, body } = options;
17
- if (!SECRET_KEY) {
18
- return { error: "RECAPT_SECRET_KEY not configured" };
19
- }
20
- const url = new URL(`${API_URL}/v1beta/query${path}`);
21
- if (params) {
22
- for (const [key, value] of Object.entries(params)) {
23
- if (value !== undefined) {
24
- url.searchParams.set(key, String(value));
25
- }
26
- }
27
- }
28
- const controller = new AbortController();
29
- const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
30
- try {
31
- const res = await fetch(url.toString(), {
32
- method,
33
- headers: {
34
- "x-private-key": SECRET_KEY,
35
- "Content-Type": "application/json",
36
- },
37
- body: body ? JSON.stringify(body) : undefined,
38
- signal: controller.signal,
39
- });
40
- clearTimeout(timeout);
41
- if (!res.ok) {
42
- const errorBody = (await res.json().catch(() => ({})));
43
- return { error: errorBody.error || `HTTP ${res.status}` };
44
- }
45
- const data = (await res.json());
46
- return { data };
47
- }
48
- catch (err) {
49
- clearTimeout(timeout);
50
- if (err instanceof Error && err.name === "AbortError") {
51
- return { error: `Request timed out after ${REQUEST_TIMEOUT_MS / 1000}s` };
52
- }
53
- return { error: err instanceof Error ? err.message : String(err) };
54
- }
55
- }
56
- export function apiGet(path, params) {
57
- return request({ method: "GET", path, params });
58
- }
59
- export function apiPost(path, body = {}) {
60
- return request({ method: "POST", path, body });
61
- }
62
- export function apiPatch(path, body = {}) {
63
- return request({ method: "PATCH", path, body });
64
- }
65
- export function apiDelete(path) {
66
- return request({ method: "DELETE", path });
67
- }
6
+ export { isApiConfigured, getApiUrl, apiGet, apiPost, apiPatch, apiDelete, } from "@glimt/mcp-tools";
@@ -30,7 +30,7 @@ function openBrowser(url) {
30
30
  });
31
31
  }
32
32
  function validateMcpKey(key) {
33
- return (key.startsWith(MCP_KEY_PREFIX) && key.length > MCP_KEY_PREFIX.length + 10);
33
+ return key.startsWith(MCP_KEY_PREFIX);
34
34
  }
35
35
  async function promptForKey() {
36
36
  const hasKey = await confirm("Do you have a Recapt MCP key?", false);
package/dist/index.d.ts CHANGED
@@ -6,14 +6,15 @@
6
6
  * Uses a search_tools + call_tool pattern to minimize context while
7
7
  * providing access to 40+ analysis tools.
8
8
  *
9
- * Exposed tools (10):
9
+ * Exposed tools (11):
10
10
  * - search_tools: Discover tools by intent
11
11
  * - call_tool: Execute discovered tools
12
12
  * - get_domains: List tracked domains
13
13
  * - run_full_diagnostic: Self-improvement entry point
14
14
  * - triage_sessions: Find sessions needing attention
15
+ * - get_upgrade_options: Check available plan upgrades
15
16
  * - memory_save, memory_recall, memory_list, memory_delete, memory_clear
16
17
  *
17
- * Hidden tools (38): Accessible via call_tool after discovery with search_tools
18
+ * Hidden tools (50+): Accessible via call_tool after discovery with search_tools
18
19
  */
19
20
  import "dotenv/config";
package/dist/index.js CHANGED
@@ -6,210 +6,44 @@
6
6
  * Uses a search_tools + call_tool pattern to minimize context while
7
7
  * providing access to 40+ analysis tools.
8
8
  *
9
- * Exposed tools (10):
9
+ * Exposed tools (11):
10
10
  * - search_tools: Discover tools by intent
11
11
  * - call_tool: Execute discovered tools
12
12
  * - get_domains: List tracked domains
13
13
  * - run_full_diagnostic: Self-improvement entry point
14
14
  * - triage_sessions: Find sessions needing attention
15
+ * - get_upgrade_options: Check available plan upgrades
15
16
  * - memory_save, memory_recall, memory_list, memory_delete, memory_clear
16
17
  *
17
- * Hidden tools (38): Accessible via call_tool after discovery with search_tools
18
+ * Hidden tools (50+): Accessible via call_tool after discovery with search_tools
18
19
  */
19
20
  import "dotenv/config";
20
21
  // @ts-ignore - MCP SDK types are complex
21
22
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
22
23
  // @ts-ignore - MCP SDK types are complex
23
24
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
24
- import { isApiConfigured, getApiUrl, apiGet, apiPost, apiPatch, apiDelete, } from "./api/client.js";
25
+ import { isApiConfigured, getApiUrl, allTools, hiddenTools, getDomainsTool, runFullDiagnosticTool, triageSessionsTool, getUpgradeOptionsTool, } from "@glimt/mcp-tools";
25
26
  import { registerSearchTools, registerCallTool, registerToolHandler, } from "./tools/catalog/index.js";
26
- // ─────────────────────────────────────────────────────────────────────────────
27
- // Exposed Tools - Registered directly with the MCP server
28
- // ─────────────────────────────────────────────────────────────────────────────
29
- import { registerGetDomains } from "./tools/getDomains.js";
30
27
  import { registerMemoryTools } from "./tools/memory.js";
31
- import { registerTriageSessions } from "./tools/triageSessions.js";
32
- import { registerDiagnosticTools } from "./tools/diagnostic.js";
33
- import { registerGetUpgradeOptions } from "./tools/upgradeOptions.js";
34
28
  // ─────────────────────────────────────────────────────────────────────────────
35
- // Hidden Tool Handlers - Registered with call_tool registry
29
+ // Tool Registration
36
30
  // ─────────────────────────────────────────────────────────────────────────────
37
- function createApiHandler(method, endpoint, buildParams) {
38
- return async (args) => {
39
- if (!isApiConfigured()) {
40
- return {
41
- content: [
42
- {
43
- type: "text",
44
- text: JSON.stringify({ error: "API not configured" }),
45
- },
46
- ],
47
- isError: true,
48
- };
49
- }
50
- const url = typeof endpoint === "function" ? endpoint(args) : endpoint;
51
- const params = buildParams ? buildParams(args) : args;
52
- const apiCall = {
53
- GET: () => apiGet(url, params),
54
- POST: () => apiPost(url, params),
55
- PATCH: () => apiPatch(url, params),
56
- DELETE: () => apiDelete(url),
57
- }[method];
58
- const { data, error } = await apiCall();
59
- if (error) {
60
- return {
61
- content: [{ type: "text", text: JSON.stringify({ error }) }],
62
- isError: true,
63
- };
64
- }
65
- return { content: [{ type: "text", text: JSON.stringify(data) }] };
66
- };
31
+ /**
32
+ * Register a tool definition with the MCP server.
33
+ * The MCP SDK accepts Zod schemas directly via .shape
34
+ */
35
+ function registerToolWithServer(server, tool) {
36
+ // Use type assertion to avoid "Type instantiation is excessively deep" error
37
+ // The MCP SDK's complex generic types cause TypeScript to struggle
38
+ server.tool(tool.name, tool.description, tool.inputSchema.shape, tool.handler);
67
39
  }
40
+ /**
41
+ * Register all hidden tools with the call_tool registry.
42
+ */
68
43
  function registerHiddenTools() {
69
- // Page Analysis
70
- registerToolHandler("get_page_metrics", createApiHandler("GET", "/pages"));
71
- registerToolHandler("get_element_friction", createApiHandler("GET", "/elements"));
72
- registerToolHandler("get_page_trends", createApiHandler("GET", "/trends"));
73
- registerToolHandler("get_dead_clicks", createApiHandler("GET", "/dead-clicks"));
74
- registerToolHandler("get_console_errors", createApiHandler("GET", "/console-errors"));
75
- registerToolHandler("get_form_friction", createApiHandler("GET", "/forms/friction"));
76
- registerToolHandler("list_pages", createApiHandler("GET", "/pages/list"));
77
- registerToolHandler("scan_site", createApiHandler("GET", "/site/overview", (args) => ({
78
- top_n: args.top_n ?? 10,
79
- offset: args.offset ?? 0,
80
- })));
81
- registerToolHandler("get_ux_health_report", createApiHandler("GET", "/health-report"));
82
- // Flow Analysis
83
- registerToolHandler("analyze_flow", createApiHandler("POST", "/flows/analyze"));
84
- registerToolHandler("analyze_funnel", createApiHandler("POST", "/flows/funnel"));
85
- registerToolHandler("get_flow_friction", createApiHandler("GET", "/flow-friction"));
86
- registerToolHandler("get_journey_patterns", createApiHandler("GET", "/flows/patterns"));
87
- // Issue Detection
88
- registerToolHandler("get_issues", createApiHandler("GET", "/issues"));
89
- registerToolHandler("get_actionable_issues", createApiHandler("GET", "/actionable-issues"));
90
- registerToolHandler("get_anomalies", createApiHandler("GET", "/anomalies"));
91
- registerToolHandler("detect_regressions", createApiHandler("GET", "/regressions"));
92
- registerToolHandler("detect_drift", createApiHandler("GET", "/drift"));
93
- // Comparison & Segmentation
94
- registerToolHandler("compare_cohorts", createApiHandler("POST", "/cohorts/compare"));
95
- registerToolHandler("compare_periods", createApiHandler("POST", "/pages/compare-periods"));
96
- registerToolHandler("discover_personas", createApiHandler("GET", "/personas"));
97
- // Session Analysis
98
- registerToolHandler("search_sessions", createApiHandler("POST", "/sessions/search"));
99
- registerToolHandler("list_sessions", createApiHandler("GET", "/sessions"));
100
- registerToolHandler("get_session_pages", async (args) => {
101
- if (!isApiConfigured()) {
102
- return {
103
- content: [
104
- {
105
- type: "text",
106
- text: JSON.stringify({ error: "API not configured" }),
107
- },
108
- ],
109
- isError: true,
110
- };
111
- }
112
- const { session_id, session_ids } = args;
113
- if (!session_id && (!session_ids || session_ids.length === 0)) {
114
- return {
115
- content: [
116
- {
117
- type: "text",
118
- text: JSON.stringify({
119
- error: "Either session_id or session_ids must be provided",
120
- }),
121
- },
122
- ],
123
- isError: true,
124
- };
125
- }
126
- const isSingleSession = session_id && !session_ids;
127
- const { data, error } = isSingleSession
128
- ? await apiGet(`/sessions/${session_id}/pages`)
129
- : await apiPost("/sessions/pages", {
130
- session_ids: session_ids ?? [session_id],
131
- });
132
- if (error) {
133
- return {
134
- content: [{ type: "text", text: JSON.stringify({ error }) }],
135
- isError: true,
136
- };
137
- }
138
- return { content: [{ type: "text", text: JSON.stringify(data) }] };
139
- });
140
- registerToolHandler("get_session_details", async (args) => {
141
- if (!isApiConfigured()) {
142
- return {
143
- content: [
144
- {
145
- type: "text",
146
- text: JSON.stringify({ error: "API not configured" }),
147
- },
148
- ],
149
- isError: true,
150
- };
151
- }
152
- const { session_id, session_ids } = args;
153
- if (!session_id && (!session_ids || session_ids.length === 0)) {
154
- return {
155
- content: [
156
- {
157
- type: "text",
158
- text: JSON.stringify({
159
- error: "Either session_id or session_ids must be provided",
160
- }),
161
- },
162
- ],
163
- isError: true,
164
- };
165
- }
166
- const isSingleSession = session_id && !session_ids;
167
- const { data, error } = isSingleSession
168
- ? await apiGet(`/sessions/${session_id}`)
169
- : await apiPost("/sessions/details", {
170
- session_ids: session_ids ?? [session_id],
171
- });
172
- if (error) {
173
- return {
174
- content: [{ type: "text", text: JSON.stringify({ error }) }],
175
- isError: true,
176
- };
177
- }
178
- return { content: [{ type: "text", text: JSON.stringify(data) }] };
179
- });
180
- registerToolHandler("predict_outcomes", createApiHandler("POST", "/predict"));
181
- // Diagnostic (investigate_issue and validate_issue - run_full_diagnostic is exposed)
182
- registerToolHandler("investigate_issue", createApiHandler("GET", (args) => `/issues/${args.issue_id}/investigate`, (args) => ({ days: args.days ?? 7 })));
183
- registerToolHandler("validate_issue", createApiHandler("POST", (args) => `/issues/${args.issue_id}/validate`, (args) => ({ lookback_days: args.lookback_days ?? 3 })));
184
- // Triage
185
- registerToolHandler("dismiss_issue", createApiHandler("POST", (args) => `/issues/${args.issue_id}/dismiss`, (args) => ({
186
- reason: args.reason,
187
- explanation: args.explanation,
188
- create_knowledge: args.create_knowledge ?? true,
189
- })));
190
- registerToolHandler("mark_intended_behavior", createApiHandler("POST", (args) => `/issues/${args.issue_id}/mark-intended`, (args) => ({ explanation: args.explanation })));
191
- registerToolHandler("get_issue_history", createApiHandler("GET", (args) => `/issues/${args.issue_id}/history`));
192
- // Remediation
193
- registerToolHandler("propose_fix", createApiHandler("POST", "/remediations"));
194
- registerToolHandler("list_pending_fixes", createApiHandler("GET", "/remediations/pending"));
195
- registerToolHandler("list_remediations", createApiHandler("GET", "/remediations"));
196
- registerToolHandler("confirm_deployment", createApiHandler("PATCH", (args) => `/remediations/${args.remediation_id}/deploy`, () => ({})));
197
- registerToolHandler("evaluate_fix", createApiHandler("POST", (args) => `/remediations/${args.remediation_id}/evaluate`, (args) => ({ min_hours: args.min_hours ?? 24 })));
198
- registerToolHandler("get_fix_history", createApiHandler("GET", (args) => `/remediations/history/${args.issue_id}`));
199
- // Knowledge
200
- registerToolHandler("get_site_knowledge", createApiHandler("GET", "/knowledge"));
201
- registerToolHandler("add_site_knowledge", createApiHandler("POST", "/knowledge", (args) => ({
202
- ...args,
203
- source: "agent",
204
- })));
205
- registerToolHandler("delete_site_knowledge", createApiHandler("DELETE", (args) => `/knowledge/${args.knowledge_id}`));
206
- registerToolHandler("get_similar_fixes", createApiHandler("GET", "/knowledge/similar-fixes"));
207
- // Improvement Runs (workflow tracking)
208
- registerToolHandler("start_improvement_run", createApiHandler("POST", "/improvement-runs"));
209
- registerToolHandler("update_improvement_run", createApiHandler("PATCH", (args) => `/improvement-runs/${args.run_id}`));
210
- registerToolHandler("record_improvement_action", createApiHandler("POST", (args) => `/improvement-runs/${args.run_id}/actions`));
211
- registerToolHandler("get_improvement_run", createApiHandler("GET", (args) => `/improvement-runs/${args.run_id}`));
212
- registerToolHandler("list_improvement_runs", createApiHandler("GET", "/improvement-runs"));
44
+ for (const tool of hiddenTools) {
45
+ registerToolHandler(tool.name, tool.handler);
46
+ }
213
47
  }
214
48
  // ─────────────────────────────────────────────────────────────────────────────
215
49
  // Server Instructions
@@ -323,17 +157,20 @@ async function main() {
323
157
  });
324
158
  // Register hidden tool handlers first (for call_tool to use)
325
159
  registerHiddenTools();
326
- // Register exposed tools
160
+ // Register search_tools and call_tool (MCP-specific implementations)
327
161
  registerSearchTools(server);
328
162
  registerCallTool(server);
329
- registerGetDomains(server);
330
- registerDiagnosticTools(server); // Includes run_full_diagnostic
331
- registerTriageSessions(server);
332
- registerGetUpgradeOptions(server);
163
+ // Register exposed tools from shared library
164
+ registerToolWithServer(server, getDomainsTool);
165
+ registerToolWithServer(server, runFullDiagnosticTool);
166
+ registerToolWithServer(server, triageSessionsTool);
167
+ registerToolWithServer(server, getUpgradeOptionsTool);
168
+ // Register memory tools (MCP-specific, stateful per session)
333
169
  registerMemoryTools(server);
334
170
  const transport = new StdioServerTransport();
335
171
  await server.connect(transport);
336
- console.error("[MCP] Server running on stdio (11 exposed tools, 38 hidden)");
172
+ console.error(`[MCP] Server running on stdio (11 exposed tools, ${hiddenTools.length} hidden)`);
173
+ console.error(`[MCP] Total tools available: ${allTools.length}`);
337
174
  }
338
175
  main().catch((err) => {
339
176
  console.error("[MCP] Fatal error:", err);