@easyfunnel/mcp 0.1.9 → 0.1.11

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.
Files changed (2) hide show
  1. package/dist/index.js +129 -4
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -94,6 +94,14 @@ var ApiClient = class {
94
94
  body: JSON.stringify(config)
95
95
  });
96
96
  }
97
+ async getConversations(projectId, params) {
98
+ const searchParams = new URLSearchParams();
99
+ if (params.limit) searchParams.set("limit", params.limit.toString());
100
+ if (params.session_id) searchParams.set("session_id", params.session_id);
101
+ return this.request(
102
+ `/projects/${projectId}/conversations?${searchParams.toString()}`
103
+ );
104
+ }
97
105
  async queryEvents(projectId, params) {
98
106
  const searchParams = new URLSearchParams();
99
107
  searchParams.set("query_type", params.query_type);
@@ -824,8 +832,8 @@ var queryEventsDefinition = {
824
832
  project_id: { type: "string", description: "Project ID" },
825
833
  query_type: {
826
834
  type: "string",
827
- enum: ["count", "recent", "breakdown", "section_engagement", "traffic_sources"],
828
- description: "Type of query"
835
+ enum: ["count", "recent", "breakdown", "section_engagement", "traffic_sources", "engagement"],
836
+ description: 'Type of query. Use "engagement" to get scroll depth and engaged time metrics.'
829
837
  },
830
838
  event_name: {
831
839
  type: "string",
@@ -863,7 +871,9 @@ async function queryEvents(client2, args) {
863
871
  `;
864
872
  output += ` Unique sessions: ${data.unique_sessions}
865
873
  `;
866
- output += ` Unique users: ${data.unique_users}
874
+ output += ` Unique visitors: ${data.unique_visitors}
875
+ `;
876
+ output += ` Identified users: ${data.identified_users}
867
877
  `;
868
878
  } else if (args.query_type === "recent") {
869
879
  output = `Recent events:
@@ -873,8 +883,43 @@ async function queryEvents(client2, args) {
873
883
  output += ` [${event.created_at}] ${event.event_name}`;
874
884
  if (event.properties?.url) output += ` \u2014 ${event.properties.url}`;
875
885
  output += "\n";
886
+ if (event.properties) {
887
+ const props = { ...event.properties };
888
+ delete props.url;
889
+ const keys = Object.keys(props);
890
+ if (keys.length > 0) {
891
+ output += ` properties: ${JSON.stringify(props)}
892
+ `;
893
+ }
894
+ }
876
895
  }
877
896
  if (!data.events?.length) output += " No events found.\n";
897
+ } else if (args.query_type === "engagement") {
898
+ output = `Engagement metrics (${args.time_range || "7d"}):
899
+
900
+ `;
901
+ output += ` Avg scroll depth: ${data.avg_scroll_depth}%
902
+ `;
903
+ output += ` Avg engaged time: ${data.avg_engaged_time}s
904
+ `;
905
+ output += ` Total engagement events: ${data.total_events}
906
+
907
+ `;
908
+ output += ` Scroll depth distribution:
909
+ `;
910
+ for (const bucket of data.scroll_depth_distribution || []) {
911
+ output += ` ${bucket.bucket}: ${bucket.count} events
912
+ `;
913
+ }
914
+ if (data.top_pages?.length) {
915
+ output += `
916
+ Top pages by scroll depth:
917
+ `;
918
+ for (const page of data.top_pages) {
919
+ output += ` ${page.url}: ${page.avg_scroll_depth}% avg, ${page.count} events
920
+ `;
921
+ }
922
+ }
878
923
  } else if (args.query_type === "section_engagement") {
879
924
  output = `Section engagement (${args.time_range || "7d"}):
880
925
 
@@ -2117,6 +2162,83 @@ The chat widget will appear as a floating bubble in the bottom-right corner of y
2117
2162
  };
2118
2163
  }
2119
2164
 
2165
+ // src/tools/query-conversations.ts
2166
+ var queryConversationsDefinition = {
2167
+ name: "query_conversations",
2168
+ description: "Read chat widget conversations from visitors. Lists recent conversations with previews, or fetches full message transcript for a specific session.",
2169
+ inputSchema: {
2170
+ type: "object",
2171
+ properties: {
2172
+ project_id: { type: "string", description: "Project ID" },
2173
+ session_id: {
2174
+ type: "string",
2175
+ description: "Specific chat session ID to fetch full transcript. If omitted, lists recent conversations."
2176
+ },
2177
+ limit: {
2178
+ type: "number",
2179
+ description: "Max conversations to return (default: 20, max: 50)"
2180
+ }
2181
+ },
2182
+ required: ["project_id"]
2183
+ }
2184
+ };
2185
+ async function queryConversations(client2, args) {
2186
+ const data = await client2.getConversations(args.project_id, {
2187
+ limit: args.limit,
2188
+ session_id: args.session_id
2189
+ });
2190
+ let output;
2191
+ if (args.session_id) {
2192
+ const s = data.session;
2193
+ output = `Conversation with ${s.user_email || "Anonymous (" + s.visitor_id.slice(0, 8) + ")"}
2194
+ `;
2195
+ output += `Country: ${s.country || "unknown"} | Device: ${s.device || "unknown"} | Browser: ${s.browser || "unknown"}
2196
+ `;
2197
+ output += `First page: ${s.first_page || "unknown"}
2198
+ `;
2199
+ output += `Started: ${s.created_at}
2200
+ `;
2201
+ output += `\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2202
+
2203
+ `;
2204
+ for (const msg of data.messages || []) {
2205
+ const label = msg.role === "user" ? "\u{1F464} Visitor" : "\u{1F916} Assistant";
2206
+ output += `${label}:
2207
+ ${msg.content}
2208
+ `;
2209
+ if (msg.page_url) output += ` [on ${msg.page_url}]
2210
+ `;
2211
+ output += "\n";
2212
+ }
2213
+ if (!data.messages?.length) output += "No messages in this conversation.\n";
2214
+ } else {
2215
+ const sessions = data.sessions || [];
2216
+ output = `Chat conversations (${sessions.length} total):
2217
+
2218
+ `;
2219
+ for (const s of sessions) {
2220
+ const visitor = s.user_email || `Anonymous (${s.visitor_id.slice(0, 8)})`;
2221
+ const country = s.country || "??";
2222
+ const device = s.device || "?";
2223
+ output += `\u2022 ${visitor} \u2014 ${country}, ${device}, ${s.message_count} msgs
2224
+ `;
2225
+ output += ` ID: ${s.id}
2226
+ `;
2227
+ if (s.preview) output += ` "${s.preview}"
2228
+ `;
2229
+ output += ` First page: ${s.first_page || "?"} | Last active: ${s.last_message_at}
2230
+
2231
+ `;
2232
+ }
2233
+ if (sessions.length === 0) {
2234
+ output += "No conversations yet.\n";
2235
+ }
2236
+ }
2237
+ return {
2238
+ content: [{ type: "text", text: output }]
2239
+ };
2240
+ }
2241
+
2120
2242
  // src/index.ts
2121
2243
  var apiKey = process.env.EASYFUNNEL_API_KEY;
2122
2244
  if (!apiKey) {
@@ -2147,7 +2269,8 @@ server.setRequestHandler(import_types.ListToolsRequestSchema, async () => ({
2147
2269
  queryEventsDefinition,
2148
2270
  deleteFunnelDefinition,
2149
2271
  updateFunnelDefinition,
2150
- setupChatWidgetDefinition
2272
+ setupChatWidgetDefinition,
2273
+ queryConversationsDefinition
2151
2274
  ]
2152
2275
  }));
2153
2276
  server.setRequestHandler(import_types.CallToolRequestSchema, async (request) => {
@@ -2183,6 +2306,8 @@ server.setRequestHandler(import_types.CallToolRequestSchema, async (request) =>
2183
2306
  return updateFunnel(client, args);
2184
2307
  case "setup_chat_widget":
2185
2308
  return setupChatWidget(client, args);
2309
+ case "query_conversations":
2310
+ return queryConversations(client, args);
2186
2311
  default:
2187
2312
  throw new Error(`Unknown tool: ${name}`);
2188
2313
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@easyfunnel/mcp",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "description": "MCP server for easyfunnel.co — AI-powered analytics tools for Claude/Cursor",
5
5
  "main": "dist/index.js",
6
6
  "bin": {