@easyfunnel/mcp 0.1.6 → 0.1.8

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 +87 -19
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -119,7 +119,26 @@ var listProjectsDefinition = {
119
119
  };
120
120
  async function listProjects(client2) {
121
121
  const projects = await client2.listProjects();
122
- return { content: [{ type: "text", text: JSON.stringify(projects, null, 2) }] };
122
+ let output = "";
123
+ if (Array.isArray(projects) && projects.length > 0) {
124
+ for (const p of projects) {
125
+ output += `Project: ${p.name}
126
+ `;
127
+ output += ` ID: ${p.id}
128
+ `;
129
+ output += ` Project API Key: ${p.api_key} (use this in the SDK / env var)
130
+ `;
131
+ output += ` Domains: ${p.domain_whitelist?.length ? p.domain_whitelist.join(", ") : "(all allowed)"}
132
+
133
+ `;
134
+ }
135
+ output += `NOTE: The "Project API Key" (ef_...) goes in your app's env var for the SDK.
136
+ `;
137
+ output += `The "Account API Key" (efa_...) is only for the MCP server \u2014 never put it in your app code.`;
138
+ } else {
139
+ output = "No projects found. Use create_project to create one.";
140
+ }
141
+ return { content: [{ type: "text", text: output }] };
123
142
  }
124
143
 
125
144
  // src/tools/create-project.ts
@@ -163,13 +182,17 @@ var import_path = require("path");
163
182
  var import_child_process = require("child_process");
164
183
  var setupSdkDefinition = {
165
184
  name: "setup_sdk",
166
- description: "Install the EasyFunnel SDK, write the env var, and wrap the app with the provider. Supports Next.js, Vite, CRA, SvelteKit, and plain HTML.",
185
+ description: "Install the EasyFunnel SDK, write the env var, and wrap the app with the provider. Supports Next.js, Vite, CRA, SvelteKit, and plain HTML. Provide either project_id (recommended) or project_api_key.",
167
186
  inputSchema: {
168
187
  type: "object",
169
188
  properties: {
189
+ project_id: {
190
+ type: "string",
191
+ description: "The project ID (UUID). The tool will look up the correct project API key (ef_...) automatically. Preferred over project_api_key."
192
+ },
170
193
  project_api_key: {
171
194
  type: "string",
172
- description: "The project API key (ef_...)"
195
+ description: "The project API key (ef_...). Use project_id instead if possible \u2014 this avoids accidentally passing the wrong key."
173
196
  },
174
197
  project_root: {
175
198
  type: "string",
@@ -181,7 +204,7 @@ var setupSdkDefinition = {
181
204
  description: "The framework used in the project"
182
205
  }
183
206
  },
184
- required: ["project_api_key", "project_root", "framework"]
207
+ required: ["project_root", "framework"]
185
208
  }
186
209
  };
187
210
  var frameworkConfigs = {
@@ -216,20 +239,48 @@ function detectPackageManager(projectRoot) {
216
239
  if ((0, import_fs.existsSync)((0, import_path.join)(projectRoot, "yarn.lock"))) return "yarn";
217
240
  return "npm";
218
241
  }
219
- async function setupSdk(args) {
220
- const { project_api_key, project_root, framework } = args;
221
- if (!project_api_key?.startsWith("ef_")) {
222
- return {
223
- content: [
224
- {
242
+ async function setupSdk(client2, args) {
243
+ const { project_root, framework } = args;
244
+ let project_api_key = args.project_api_key || "";
245
+ if (args.project_id && !project_api_key) {
246
+ try {
247
+ const projects = await client2.listProjects();
248
+ const project = projects.find((p) => p.id === args.project_id);
249
+ if (project?.api_key) {
250
+ project_api_key = project.api_key;
251
+ } else {
252
+ return {
253
+ content: [{
254
+ type: "text",
255
+ text: `Error: Project ID "${args.project_id}" not found. Run list_projects to see your projects.`
256
+ }]
257
+ };
258
+ }
259
+ } catch (err) {
260
+ return {
261
+ content: [{
225
262
  type: "text",
226
- text: `Error: Invalid API key format. Project keys start with "ef_". Got: "${project_api_key || "(empty)"}"
263
+ text: `Error: Could not look up project: ${err.message}`
264
+ }]
265
+ };
266
+ }
267
+ }
268
+ if (!project_api_key?.startsWith("ef_")) {
269
+ const hint = project_api_key?.startsWith("efa_") ? `
227
270
 
228
- Account keys ("efa_") are for the MCP server, not the SDK. Use list_projects to find your project API key.`
229
- }
230
- ]
271
+ You passed an account API key (efa_...). That key is for the MCP server, not the SDK.
272
+ Use project_id instead, or run list_projects to find the correct project API key (ef_...).` : `
273
+
274
+ Use project_id instead of project_api_key \u2014 the tool will look up the correct key automatically.`;
275
+ return {
276
+ content: [{
277
+ type: "text",
278
+ text: `Error: Invalid API key format. Project keys start with "ef_". Got: "${project_api_key || "(empty)"}"
279
+ ${hint}`
280
+ }]
231
281
  };
232
282
  }
283
+ const config = framework !== "html" ? frameworkConfigs[framework] : null;
233
284
  if (framework === "html") {
234
285
  return {
235
286
  content: [
@@ -241,6 +292,9 @@ Add this script tag to your <head>:
241
292
 
242
293
  <script defer data-api-key="${project_api_key}" src="https://easyfunnel.co/sdk.js"></script>
243
294
 
295
+ Project API Key: ${project_api_key}
296
+ (This is the PROJECT key for the SDK \u2014 not the account key used by the MCP server.)
297
+
244
298
  This will automatically track page views and clicks on elements with data-ef-track attributes.
245
299
 
246
300
  Next: After adding the script, I'll verify everything works with a test event.`
@@ -248,7 +302,6 @@ Next: After adding the script, I'll verify everything works with a test event.`
248
302
  ]
249
303
  };
250
304
  }
251
- const config = frameworkConfigs[framework];
252
305
  const steps = [];
253
306
  const filesModified = [];
254
307
  const pm = detectPackageManager(project_root);
@@ -268,8 +321,16 @@ Next: After adding the script, I'll verify everything works with a test event.`
268
321
  if (!content.includes(config.envVarName)) {
269
322
  (0, import_fs.writeFileSync)(envPath, content.trimEnd() + "\n" + envLine + "\n");
270
323
  envWritten = true;
324
+ } else if (!content.includes(envLine)) {
325
+ const updated = content.replace(
326
+ new RegExp(`^${config.envVarName}=.*$`, "m"),
327
+ envLine
328
+ );
329
+ (0, import_fs.writeFileSync)(envPath, updated);
330
+ envWritten = true;
331
+ steps.push(`[done] Updated ${config.envVarName} to new API key in ${config.envFile}`);
271
332
  } else {
272
- steps.push(`[skip] ${config.envVarName} already exists in ${config.envFile}`);
333
+ steps.push(`[skip] ${config.envVarName} already set correctly in ${config.envFile}`);
273
334
  }
274
335
  } else {
275
336
  (0, import_fs.writeFileSync)(envPath, envLine + "\n");
@@ -278,8 +339,8 @@ Next: After adding the script, I'll verify everything works with a test event.`
278
339
  if (envWritten) {
279
340
  const verifyContent = (0, import_fs.readFileSync)(envPath, "utf-8");
280
341
  if (verifyContent.includes(project_api_key)) {
281
- steps.push(`[done] Added ${config.envVarName}=${project_api_key.slice(0, 8)}... to ${config.envFile}`);
282
- filesModified.push({ file: config.envFile, action: "Added API key" });
342
+ steps.push(`[done] Set ${config.envVarName}=${project_api_key} in ${config.envFile}`);
343
+ filesModified.push({ file: config.envFile, action: "Set project API key" });
283
344
  } else {
284
345
  steps.push(`[FAIL] Wrote to ${config.envFile} but verification failed`);
285
346
  }
@@ -348,6 +409,13 @@ Files modified:
348
409
  }
349
410
  }
350
411
  output += `
412
+ Project API Key: ${project_api_key}
413
+ `;
414
+ output += `Env var: ${config.envVarName}=${project_api_key}
415
+ `;
416
+ output += `(This is the PROJECT key for the SDK \u2014 not the account key used by the MCP server.)
417
+ `;
418
+ output += `
351
419
  IMPORTANT: Restart your dev server for the env var to take effect.
352
420
  `;
353
421
  output += `
@@ -2077,7 +2145,7 @@ server.setRequestHandler(import_types.CallToolRequestSchema, async (request) =>
2077
2145
  case "scan_codebase":
2078
2146
  return scanCodebase(client, args);
2079
2147
  case "setup_sdk":
2080
- return setupSdk(args);
2148
+ return setupSdk(client, args);
2081
2149
  case "validate_setup":
2082
2150
  return validateSetup(client, args);
2083
2151
  case "recommend_funnels":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@easyfunnel/mcp",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "MCP server for easyfunnel.co — AI-powered analytics tools for Claude/Cursor",
5
5
  "main": "dist/index.js",
6
6
  "bin": {