@posthog/wizard 1.2.1 → 1.3.0
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/README.md +28 -0
- package/dist/src/nextjs/docs.d.ts +4 -0
- package/dist/src/nextjs/docs.js +67 -38
- package/dist/src/nextjs/docs.js.map +1 -1
- package/dist/src/nextjs/nextjs-wizard.js +62 -7
- package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
- package/dist/src/run.js +13 -3
- package/dist/src/run.js.map +1 -1
- package/dist/src/steps/add-mcp-server-to-clients/MCPClient.d.ts +19 -3
- package/dist/src/steps/add-mcp-server-to-clients/MCPClient.js +102 -1
- package/dist/src/steps/add-mcp-server-to-clients/MCPClient.js.map +1 -1
- package/dist/src/steps/add-mcp-server-to-clients/clients/__tests__/claude.test.js +34 -16
- package/dist/src/steps/add-mcp-server-to-clients/clients/__tests__/claude.test.js.map +1 -1
- package/dist/src/steps/add-mcp-server-to-clients/clients/claude.d.ts +42 -29
- package/dist/src/steps/add-mcp-server-to-clients/clients/claude.js +6 -61
- package/dist/src/steps/add-mcp-server-to-clients/clients/claude.js.map +1 -1
- package/dist/src/steps/add-mcp-server-to-clients/clients/cursor.d.ts +42 -29
- package/dist/src/steps/add-mcp-server-to-clients/clients/cursor.js +5 -62
- package/dist/src/steps/add-mcp-server-to-clients/clients/cursor.js.map +1 -1
- package/dist/src/steps/add-mcp-server-to-clients/defaults.d.ts +38 -22
- package/dist/src/steps/add-mcp-server-to-clients/defaults.js +7 -5
- package/dist/src/steps/add-mcp-server-to-clients/defaults.js.map +1 -1
- package/dist/src/steps/add-mcp-server-to-clients/index.js +2 -2
- package/dist/src/steps/add-mcp-server-to-clients/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/src/steps/add-mcp-server-to-clients/clients/__tests__/cursor.test.d.ts +0 -1
- package/dist/src/steps/add-mcp-server-to-clients/clients/__tests__/cursor.test.js +0 -443
- package/dist/src/steps/add-mcp-server-to-clients/clients/__tests__/cursor.test.js.map +0 -1
|
@@ -1,31 +1,47 @@
|
|
|
1
1
|
import z from 'zod';
|
|
2
2
|
export declare const DefaultMCPClientConfig: z.ZodObject<{
|
|
3
3
|
mcpServers: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
4
|
-
command: z.ZodString
|
|
5
|
-
args: z.ZodArray<z.ZodString, "many"
|
|
6
|
-
env: z.ZodRecord<z.ZodString, z.ZodString
|
|
4
|
+
command: z.ZodOptional<z.ZodString>;
|
|
5
|
+
args: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
6
|
+
env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
7
7
|
}, "strip", z.ZodTypeAny, {
|
|
8
|
-
command
|
|
9
|
-
args
|
|
10
|
-
env
|
|
8
|
+
command?: string | undefined;
|
|
9
|
+
args?: string[] | undefined;
|
|
10
|
+
env?: Record<string, string> | undefined;
|
|
11
11
|
}, {
|
|
12
|
-
command
|
|
13
|
-
args
|
|
14
|
-
env
|
|
12
|
+
command?: string | undefined;
|
|
13
|
+
args?: string[] | undefined;
|
|
14
|
+
env?: Record<string, string> | undefined;
|
|
15
15
|
}>>;
|
|
16
|
-
}, "
|
|
17
|
-
mcpServers:
|
|
18
|
-
command:
|
|
19
|
-
args:
|
|
20
|
-
env:
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
16
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
17
|
+
mcpServers: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
18
|
+
command: z.ZodOptional<z.ZodString>;
|
|
19
|
+
args: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
20
|
+
env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
21
|
+
}, "strip", z.ZodTypeAny, {
|
|
22
|
+
command?: string | undefined;
|
|
23
|
+
args?: string[] | undefined;
|
|
24
|
+
env?: Record<string, string> | undefined;
|
|
25
|
+
}, {
|
|
26
|
+
command?: string | undefined;
|
|
27
|
+
args?: string[] | undefined;
|
|
28
|
+
env?: Record<string, string> | undefined;
|
|
29
|
+
}>>;
|
|
30
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
31
|
+
mcpServers: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
32
|
+
command: z.ZodOptional<z.ZodString>;
|
|
33
|
+
args: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
34
|
+
env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
35
|
+
}, "strip", z.ZodTypeAny, {
|
|
36
|
+
command?: string | undefined;
|
|
37
|
+
args?: string[] | undefined;
|
|
38
|
+
env?: Record<string, string> | undefined;
|
|
39
|
+
}, {
|
|
40
|
+
command?: string | undefined;
|
|
41
|
+
args?: string[] | undefined;
|
|
42
|
+
env?: Record<string, string> | undefined;
|
|
43
|
+
}>>;
|
|
44
|
+
}, z.ZodTypeAny, "passthrough">>;
|
|
29
45
|
export declare const getDefaultServerConfig: (apiKey: string) => {
|
|
30
46
|
command: string;
|
|
31
47
|
args: string[];
|
|
@@ -5,13 +5,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.getDefaultServerConfig = exports.DefaultMCPClientConfig = void 0;
|
|
7
7
|
const zod_1 = __importDefault(require("zod"));
|
|
8
|
-
exports.DefaultMCPClientConfig = zod_1.default
|
|
8
|
+
exports.DefaultMCPClientConfig = zod_1.default
|
|
9
|
+
.object({
|
|
9
10
|
mcpServers: zod_1.default.record(zod_1.default.string(), zod_1.default.object({
|
|
10
|
-
command: zod_1.default.string(),
|
|
11
|
-
args: zod_1.default.array(zod_1.default.string()),
|
|
12
|
-
env: zod_1.default.record(zod_1.default.string(), zod_1.default.string()),
|
|
11
|
+
command: zod_1.default.string().optional(),
|
|
12
|
+
args: zod_1.default.array(zod_1.default.string()).optional(),
|
|
13
|
+
env: zod_1.default.record(zod_1.default.string(), zod_1.default.string()).optional(),
|
|
13
14
|
})),
|
|
14
|
-
})
|
|
15
|
+
})
|
|
16
|
+
.passthrough();
|
|
15
17
|
const getDefaultServerConfig = (apiKey) => ({
|
|
16
18
|
command: 'npx',
|
|
17
19
|
args: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../../../src/steps/add-mcp-server-to-clients/defaults.ts"],"names":[],"mappings":";;;;;;AAAA,8CAAoB;AAEP,QAAA,sBAAsB,GAAG,aAAC,
|
|
1
|
+
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../../../src/steps/add-mcp-server-to-clients/defaults.ts"],"names":[],"mappings":";;;;;;AAAA,8CAAoB;AAEP,QAAA,sBAAsB,GAAG,aAAC;KACpC,MAAM,CAAC;IACN,UAAU,EAAE,aAAC,CAAC,MAAM,CAClB,aAAC,CAAC,MAAM,EAAE,EACV,aAAC,CAAC,MAAM,CAAC;QACP,OAAO,EAAE,aAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC9B,IAAI,EAAE,aAAC,CAAC,KAAK,CAAC,aAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;QACpC,GAAG,EAAE,aAAC,CAAC,MAAM,CAAC,aAAC,CAAC,MAAM,EAAE,EAAE,aAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;KACjD,CAAC,CACH;CACF,CAAC;KACD,WAAW,EAAE,CAAC;AAEV,MAAM,sBAAsB,GAAG,CAAC,MAAc,EAAE,EAAE,CAAC,CAAC;IACzD,OAAO,EAAE,KAAK;IACd,IAAI,EAAE;QACJ,IAAI;QACJ,mBAAmB;QACnB,6BAA6B;QAC7B,UAAU;QACV,uCAAuC;KACxC;IACD,GAAG,EAAE;QACH,mBAAmB,EAAE,UAAU,MAAM,EAAE;KACxC;CACF,CAAC,CAAC;AAZU,QAAA,sBAAsB,0BAYhC","sourcesContent":["import z from 'zod';\n\nexport const DefaultMCPClientConfig = z\n .object({\n mcpServers: z.record(\n z.string(),\n z.object({\n command: z.string().optional(),\n args: z.array(z.string()).optional(),\n env: z.record(z.string(), z.string()).optional(),\n }),\n ),\n })\n .passthrough();\n\nexport const getDefaultServerConfig = (apiKey: string) => ({\n command: 'npx',\n args: [\n '-y',\n 'mcp-remote@latest',\n 'https://mcp.posthog.com/sse',\n '--header',\n `Authorization:\\${POSTHOG_AUTH_HEADER}`,\n ],\n env: {\n POSTHOG_AUTH_HEADER: `Bearer ${apiKey}`,\n },\n});\n"]}
|
|
@@ -41,7 +41,7 @@ const addMCPServerToClientsStep = async ({ integration, cloudRegion, askPermissi
|
|
|
41
41
|
clack_1.default.log.warn(`The PostHog MCP server is already configured for:
|
|
42
42
|
|
|
43
43
|
${installedClients.map((c) => `- ${c.name}`).join('\n ')}`);
|
|
44
|
-
const reinstall = await clack_1.default.select({
|
|
44
|
+
const reinstall = await (0, clack_utils_1.abortIfCancelled)(clack_1.default.select({
|
|
45
45
|
message: 'Would you like to reinstall it?',
|
|
46
46
|
options: [
|
|
47
47
|
{
|
|
@@ -55,7 +55,7 @@ const addMCPServerToClientsStep = async ({ integration, cloudRegion, askPermissi
|
|
|
55
55
|
hint: 'Keep the existing installation',
|
|
56
56
|
},
|
|
57
57
|
],
|
|
58
|
-
});
|
|
58
|
+
}), integration);
|
|
59
59
|
if (!reinstall) {
|
|
60
60
|
analytics_1.analytics.capture('wizard interaction', {
|
|
61
61
|
action: 'declined to reinstall mcp servers',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/steps/add-mcp-server-to-clients/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Integration } from '../../lib/constants';\nimport { traceStep } from '../../telemetry';\nimport { analytics } from '../../utils/analytics';\nimport clack from '../../utils/clack';\nimport {\n abort,\n abortIfCancelled,\n askForCloudRegion,\n} from '../../utils/clack-utils';\nimport { MCPClient } from './MCPClient';\nimport { CursorMCPClient } from './clients/cursor';\nimport { ClaudeMCPClient } from './clients/claude';\nimport { getPersonalApiKey } from '../../mcp';\nimport type { CloudRegion } from '../../utils/types';\n\nexport const getSupportedClients = (): MCPClient[] => {\n return [new CursorMCPClient(), new ClaudeMCPClient()].filter((client) =>\n client.isClientSupported(),\n );\n};\n\nexport const addMCPServerToClientsStep = async ({\n integration,\n cloudRegion,\n askPermission = true,\n}: {\n integration?: Integration;\n cloudRegion?: CloudRegion;\n askPermission?: boolean;\n}): Promise<string[]> => {\n const region = cloudRegion ?? (await askForCloudRegion());\n\n if (region === 'eu') {\n if (!askPermission) {\n await abort(\n 'The MCP server is not available in the EU region. It is coming soon!',\n );\n }\n return [];\n }\n\n const hasPermission = askPermission\n ? await abortIfCancelled(\n clack.select({\n message:\n 'Would you like to install the PostHog MCP server to use PostHog in your editor?',\n options: [\n { value: true, label: 'Yes' },\n { value: false, label: 'No' },\n ],\n }),\n integration,\n )\n : true;\n\n if (!hasPermission) {\n return [];\n }\n\n const clients = getSupportedClients();\n\n const installedClients = await getInstalledClients();\n\n if (installedClients.length > 0) {\n clack.log.warn(\n `The PostHog MCP server is already configured for:\n\n ${installedClients.map((c) => `- ${c.name}`).join('\\n ')}`,\n );\n\n const reinstall = await clack.select({\n message: 'Would you like to reinstall it?',\n options: [\n {\n value: true,\n label: 'Yes',\n hint: 'Reinstall the MCP server',\n },\n {\n value: false,\n label: 'No',\n hint: 'Keep the existing installation',\n },\n ],\n });\n\n if (!reinstall) {\n analytics.capture('wizard interaction', {\n action: 'declined to reinstall mcp servers',\n clients: installedClients.map((c) => c.name),\n integration,\n });\n\n return [];\n }\n\n await removeMCPServer(installedClients);\n clack.log.info('Removed existing installation.');\n }\n\n const personalApiKey = await getPersonalApiKey({ cloudRegion: region });\n\n await traceStep('adding mcp servers', async () => {\n await addMCPServer(clients, personalApiKey);\n });\n\n clack.log.success(\n `Added the PostHog MCP server to:\n ${clients.map((c) => `- ${c.name}`).join('\\n ')} `,\n );\n\n analytics.capture('wizard interaction', {\n action: 'added mcp servers',\n clients: clients.map((c) => c.name),\n integration,\n });\n\n return clients.map((c) => c.name);\n};\n\nexport const removeMCPServerFromClientsStep = async ({\n integration,\n}: {\n integration?: Integration;\n}): Promise<string[]> => {\n const installedClients = await getInstalledClients();\n\n if (installedClients.length === 0) {\n analytics.capture('wizard interaction', {\n action: 'no mcp servers to remove',\n integration,\n });\n return [];\n }\n\n const removeServers: boolean = await abortIfCancelled(\n clack.select({\n message: `Found the PostHog MCP server in ${installedClients.length} clients. Would you like to remove it?`,\n options: [\n {\n value: true,\n label: 'Yes',\n hint: `Remove PostHog MCP server`,\n },\n {\n value: false,\n label: 'No',\n hint: 'Keep the MCP server configuration',\n },\n ],\n }),\n integration,\n );\n\n if (!removeServers) {\n analytics.capture('wizard interaction', {\n action: 'declined to remove mcp servers',\n clients: installedClients.map((c) => c.name),\n integration,\n });\n\n await abort('The MCP server was not removed.');\n return [];\n }\n\n const results = await traceStep('removing mcp servers', async () => {\n await removeMCPServer(installedClients);\n\n return installedClients.map((c) => c.name);\n });\n\n analytics.capture('wizard interaction', {\n action: 'removed mcp servers',\n clients: results,\n integration,\n });\n\n return results;\n};\n\nexport const getInstalledClients = async (): Promise<MCPClient[]> => {\n const clients = getSupportedClients();\n\n const installedClients: MCPClient[] = [];\n\n for (const client of clients) {\n if (await client.isServerInstalled()) {\n installedClients.push(client);\n }\n }\n\n return installedClients;\n};\n\nexport const addMCPServer = async (\n clients: MCPClient[],\n personalApiKey: string,\n): Promise<void> => {\n for (const client of clients) {\n await client.addServer(personalApiKey);\n }\n};\n\nexport const removeMCPServer = async (clients: MCPClient[]): Promise<void> => {\n for (const client of clients) {\n await client.removeServer();\n }\n};\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/steps/add-mcp-server-to-clients/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Integration } from '../../lib/constants';\nimport { traceStep } from '../../telemetry';\nimport { analytics } from '../../utils/analytics';\nimport clack from '../../utils/clack';\nimport {\n abort,\n abortIfCancelled,\n askForCloudRegion,\n} from '../../utils/clack-utils';\nimport { MCPClient } from './MCPClient';\nimport { CursorMCPClient } from './clients/cursor';\nimport { ClaudeMCPClient } from './clients/claude';\nimport { getPersonalApiKey } from '../../mcp';\nimport type { CloudRegion } from '../../utils/types';\n\nexport const getSupportedClients = (): MCPClient[] => {\n return [new CursorMCPClient(), new ClaudeMCPClient()].filter((client) =>\n client.isClientSupported(),\n );\n};\n\nexport const addMCPServerToClientsStep = async ({\n integration,\n cloudRegion,\n askPermission = true,\n}: {\n integration?: Integration;\n cloudRegion?: CloudRegion;\n askPermission?: boolean;\n}): Promise<string[]> => {\n const region = cloudRegion ?? (await askForCloudRegion());\n\n if (region === 'eu') {\n if (!askPermission) {\n await abort(\n 'The MCP server is not available in the EU region. It is coming soon!',\n );\n }\n return [];\n }\n\n const hasPermission = askPermission\n ? await abortIfCancelled(\n clack.select({\n message:\n 'Would you like to install the PostHog MCP server to use PostHog in your editor?',\n options: [\n { value: true, label: 'Yes' },\n { value: false, label: 'No' },\n ],\n }),\n integration,\n )\n : true;\n\n if (!hasPermission) {\n return [];\n }\n\n const clients = getSupportedClients();\n\n const installedClients = await getInstalledClients();\n\n if (installedClients.length > 0) {\n clack.log.warn(\n `The PostHog MCP server is already configured for:\n\n ${installedClients.map((c) => `- ${c.name}`).join('\\n ')}`,\n );\n\n const reinstall = await abortIfCancelled(\n clack.select({\n message: 'Would you like to reinstall it?',\n options: [\n {\n value: true,\n label: 'Yes',\n hint: 'Reinstall the MCP server',\n },\n {\n value: false,\n label: 'No',\n hint: 'Keep the existing installation',\n },\n ],\n }),\n integration,\n );\n\n if (!reinstall) {\n analytics.capture('wizard interaction', {\n action: 'declined to reinstall mcp servers',\n clients: installedClients.map((c) => c.name),\n integration,\n });\n\n return [];\n }\n\n await removeMCPServer(installedClients);\n clack.log.info('Removed existing installation.');\n }\n\n const personalApiKey = await getPersonalApiKey({ cloudRegion: region });\n\n await traceStep('adding mcp servers', async () => {\n await addMCPServer(clients, personalApiKey);\n });\n\n clack.log.success(\n `Added the PostHog MCP server to:\n ${clients.map((c) => `- ${c.name}`).join('\\n ')} `,\n );\n\n analytics.capture('wizard interaction', {\n action: 'added mcp servers',\n clients: clients.map((c) => c.name),\n integration,\n });\n\n return clients.map((c) => c.name);\n};\n\nexport const removeMCPServerFromClientsStep = async ({\n integration,\n}: {\n integration?: Integration;\n}): Promise<string[]> => {\n const installedClients = await getInstalledClients();\n\n if (installedClients.length === 0) {\n analytics.capture('wizard interaction', {\n action: 'no mcp servers to remove',\n integration,\n });\n return [];\n }\n\n const removeServers: boolean = await abortIfCancelled(\n clack.select({\n message: `Found the PostHog MCP server in ${installedClients.length} clients. Would you like to remove it?`,\n options: [\n {\n value: true,\n label: 'Yes',\n hint: `Remove PostHog MCP server`,\n },\n {\n value: false,\n label: 'No',\n hint: 'Keep the MCP server configuration',\n },\n ],\n }),\n integration,\n );\n\n if (!removeServers) {\n analytics.capture('wizard interaction', {\n action: 'declined to remove mcp servers',\n clients: installedClients.map((c) => c.name),\n integration,\n });\n\n await abort('The MCP server was not removed.');\n return [];\n }\n\n const results = await traceStep('removing mcp servers', async () => {\n await removeMCPServer(installedClients);\n\n return installedClients.map((c) => c.name);\n });\n\n analytics.capture('wizard interaction', {\n action: 'removed mcp servers',\n clients: results,\n integration,\n });\n\n return results;\n};\n\nexport const getInstalledClients = async (): Promise<MCPClient[]> => {\n const clients = getSupportedClients();\n\n const installedClients: MCPClient[] = [];\n\n for (const client of clients) {\n if (await client.isServerInstalled()) {\n installedClients.push(client);\n }\n }\n\n return installedClients;\n};\n\nexport const addMCPServer = async (\n clients: MCPClient[],\n personalApiKey: string,\n): Promise<void> => {\n for (const client of clients) {\n await client.addServer(personalApiKey);\n }\n};\n\nexport const removeMCPServer = async (clients: MCPClient[]): Promise<void> => {\n for (const client of clients) {\n await client.removeServer();\n }\n};\n"]}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,443 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
const fs = __importStar(require("fs"));
|
|
37
|
-
const path = __importStar(require("path"));
|
|
38
|
-
const os = __importStar(require("os"));
|
|
39
|
-
const cursor_1 = require("../cursor");
|
|
40
|
-
const defaults_1 = require("../../defaults");
|
|
41
|
-
jest.mock('fs', () => ({
|
|
42
|
-
promises: {
|
|
43
|
-
mkdir: jest.fn(),
|
|
44
|
-
readFile: jest.fn(),
|
|
45
|
-
writeFile: jest.fn(),
|
|
46
|
-
},
|
|
47
|
-
existsSync: jest.fn(),
|
|
48
|
-
}));
|
|
49
|
-
jest.mock('os', () => ({
|
|
50
|
-
homedir: jest.fn(),
|
|
51
|
-
}));
|
|
52
|
-
jest.mock('../../defaults', () => ({
|
|
53
|
-
DefaultMCPClientConfig: {
|
|
54
|
-
parse: jest.fn(),
|
|
55
|
-
},
|
|
56
|
-
getDefaultServerConfig: jest.fn(),
|
|
57
|
-
}));
|
|
58
|
-
jest.mock('lodash', () => ({
|
|
59
|
-
merge: jest.fn(),
|
|
60
|
-
}));
|
|
61
|
-
describe('CursorMCPClient', () => {
|
|
62
|
-
let client;
|
|
63
|
-
const mockHomeDir = '/mock/home';
|
|
64
|
-
const mockApiKey = 'test-api-key';
|
|
65
|
-
const mockServerConfig = {
|
|
66
|
-
command: 'npx',
|
|
67
|
-
args: ['-y', 'mcp-remote@latest'],
|
|
68
|
-
env: { POSTHOG_AUTH_HEADER: `Bearer ${mockApiKey}` },
|
|
69
|
-
};
|
|
70
|
-
const mkdirMock = fs.promises.mkdir;
|
|
71
|
-
const readFileMock = fs.promises.readFile;
|
|
72
|
-
const writeFileMock = fs.promises.writeFile;
|
|
73
|
-
const existsSyncMock = fs.existsSync;
|
|
74
|
-
const homedirMock = os.homedir;
|
|
75
|
-
const getDefaultServerConfigMock = defaults_1.getDefaultServerConfig;
|
|
76
|
-
const mergeMock = require('lodash').merge;
|
|
77
|
-
const originalPlatform = process.platform;
|
|
78
|
-
beforeEach(() => {
|
|
79
|
-
client = new cursor_1.CursorMCPClient();
|
|
80
|
-
jest.clearAllMocks();
|
|
81
|
-
// Reset all mocks to their default implementations
|
|
82
|
-
mkdirMock.mockResolvedValue(undefined);
|
|
83
|
-
readFileMock.mockResolvedValue('{}');
|
|
84
|
-
writeFileMock.mockResolvedValue(undefined);
|
|
85
|
-
existsSyncMock.mockReturnValue(false);
|
|
86
|
-
homedirMock.mockReturnValue(mockHomeDir);
|
|
87
|
-
getDefaultServerConfigMock.mockReturnValue(mockServerConfig);
|
|
88
|
-
mergeMock.mockImplementation((target, ...sources) => Object.assign(target, ...sources));
|
|
89
|
-
// Mock the Zod schema parse method
|
|
90
|
-
const { DefaultMCPClientConfig } = require('../../defaults');
|
|
91
|
-
DefaultMCPClientConfig.parse.mockImplementation((data) => data);
|
|
92
|
-
});
|
|
93
|
-
afterEach(() => {
|
|
94
|
-
Object.defineProperty(process, 'platform', {
|
|
95
|
-
value: originalPlatform,
|
|
96
|
-
writable: true,
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
describe('constructor', () => {
|
|
100
|
-
it('should set the correct name', () => {
|
|
101
|
-
expect(client.name).toBe('Cursor');
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
describe('isClientSupported', () => {
|
|
105
|
-
it('should return true for macOS', () => {
|
|
106
|
-
Object.defineProperty(process, 'platform', {
|
|
107
|
-
value: 'darwin',
|
|
108
|
-
writable: true,
|
|
109
|
-
});
|
|
110
|
-
expect(client.isClientSupported()).toBe(true);
|
|
111
|
-
});
|
|
112
|
-
it('should return true for Windows', () => {
|
|
113
|
-
Object.defineProperty(process, 'platform', {
|
|
114
|
-
value: 'win32',
|
|
115
|
-
writable: true,
|
|
116
|
-
});
|
|
117
|
-
expect(client.isClientSupported()).toBe(true);
|
|
118
|
-
});
|
|
119
|
-
it('should return false for Linux', () => {
|
|
120
|
-
Object.defineProperty(process, 'platform', {
|
|
121
|
-
value: 'linux',
|
|
122
|
-
writable: true,
|
|
123
|
-
});
|
|
124
|
-
expect(client.isClientSupported()).toBe(false);
|
|
125
|
-
});
|
|
126
|
-
it('should return false for other platforms', () => {
|
|
127
|
-
Object.defineProperty(process, 'platform', {
|
|
128
|
-
value: 'freebsd',
|
|
129
|
-
writable: true,
|
|
130
|
-
});
|
|
131
|
-
expect(client.isClientSupported()).toBe(false);
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
describe('getConfigPath', () => {
|
|
135
|
-
it('should return correct path using homedir', () => {
|
|
136
|
-
const configPath = client.getConfigPath();
|
|
137
|
-
expect(configPath).toBe(path.join(mockHomeDir, '.cursor', 'mcp.json'));
|
|
138
|
-
expect(homedirMock).toHaveBeenCalled();
|
|
139
|
-
});
|
|
140
|
-
it('should work with different home directories', () => {
|
|
141
|
-
const differentHome = '/different/home';
|
|
142
|
-
homedirMock.mockReturnValue(differentHome);
|
|
143
|
-
const configPath = client.getConfigPath();
|
|
144
|
-
expect(configPath).toBe(path.join(differentHome, '.cursor', 'mcp.json'));
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
describe('isServerInstalled', () => {
|
|
148
|
-
it('should return false when config file does not exist', async () => {
|
|
149
|
-
existsSyncMock.mockReturnValue(false);
|
|
150
|
-
const result = await client.isServerInstalled();
|
|
151
|
-
expect(result).toBe(false);
|
|
152
|
-
expect(readFileMock).not.toHaveBeenCalled();
|
|
153
|
-
});
|
|
154
|
-
it('should return false when config file exists but posthog server is not configured', async () => {
|
|
155
|
-
existsSyncMock.mockReturnValue(true);
|
|
156
|
-
const configData = {
|
|
157
|
-
mcpServers: {
|
|
158
|
-
otherServer: mockServerConfig,
|
|
159
|
-
},
|
|
160
|
-
};
|
|
161
|
-
readFileMock.mockResolvedValue(JSON.stringify(configData));
|
|
162
|
-
const result = await client.isServerInstalled();
|
|
163
|
-
expect(result).toBe(false);
|
|
164
|
-
});
|
|
165
|
-
it('should return true when posthog server is configured', async () => {
|
|
166
|
-
existsSyncMock.mockReturnValue(true);
|
|
167
|
-
const configData = {
|
|
168
|
-
mcpServers: {
|
|
169
|
-
posthog: mockServerConfig,
|
|
170
|
-
otherServer: mockServerConfig,
|
|
171
|
-
},
|
|
172
|
-
};
|
|
173
|
-
readFileMock.mockResolvedValue(JSON.stringify(configData));
|
|
174
|
-
const result = await client.isServerInstalled();
|
|
175
|
-
expect(result).toBe(true);
|
|
176
|
-
});
|
|
177
|
-
it('should return true when only posthog server is configured', async () => {
|
|
178
|
-
existsSyncMock.mockReturnValue(true);
|
|
179
|
-
const configData = {
|
|
180
|
-
mcpServers: {
|
|
181
|
-
posthog: mockServerConfig,
|
|
182
|
-
},
|
|
183
|
-
};
|
|
184
|
-
readFileMock.mockResolvedValue(JSON.stringify(configData));
|
|
185
|
-
const result = await client.isServerInstalled();
|
|
186
|
-
expect(result).toBe(true);
|
|
187
|
-
});
|
|
188
|
-
it('should return false when config file is invalid JSON', async () => {
|
|
189
|
-
existsSyncMock.mockReturnValue(true);
|
|
190
|
-
readFileMock.mockResolvedValue('invalid json');
|
|
191
|
-
const result = await client.isServerInstalled();
|
|
192
|
-
expect(result).toBe(false);
|
|
193
|
-
});
|
|
194
|
-
it('should return false when config file is empty', async () => {
|
|
195
|
-
existsSyncMock.mockReturnValue(true);
|
|
196
|
-
readFileMock.mockResolvedValue('');
|
|
197
|
-
const result = await client.isServerInstalled();
|
|
198
|
-
expect(result).toBe(false);
|
|
199
|
-
});
|
|
200
|
-
it('should return false when readFile throws an error', async () => {
|
|
201
|
-
existsSyncMock.mockReturnValue(true);
|
|
202
|
-
readFileMock.mockRejectedValue(new Error('File read error'));
|
|
203
|
-
const result = await client.isServerInstalled();
|
|
204
|
-
expect(result).toBe(false);
|
|
205
|
-
});
|
|
206
|
-
it('should return false when Zod parsing fails', async () => {
|
|
207
|
-
existsSyncMock.mockReturnValue(true);
|
|
208
|
-
readFileMock.mockResolvedValue(JSON.stringify({ invalid: 'config' }));
|
|
209
|
-
const { DefaultMCPClientConfig } = require('../../defaults');
|
|
210
|
-
DefaultMCPClientConfig.parse.mockImplementation(() => {
|
|
211
|
-
throw new Error('Zod validation error');
|
|
212
|
-
});
|
|
213
|
-
const result = await client.isServerInstalled();
|
|
214
|
-
expect(result).toBe(false);
|
|
215
|
-
});
|
|
216
|
-
it('should handle config with empty mcpServers', async () => {
|
|
217
|
-
existsSyncMock.mockReturnValue(true);
|
|
218
|
-
const configData = {
|
|
219
|
-
mcpServers: {},
|
|
220
|
-
};
|
|
221
|
-
readFileMock.mockResolvedValue(JSON.stringify(configData));
|
|
222
|
-
const result = await client.isServerInstalled();
|
|
223
|
-
expect(result).toBe(false);
|
|
224
|
-
});
|
|
225
|
-
});
|
|
226
|
-
describe('addServer', () => {
|
|
227
|
-
it('should create config directory and add server when config file does not exist', async () => {
|
|
228
|
-
existsSyncMock.mockReturnValue(false);
|
|
229
|
-
mergeMock.mockReturnValue({
|
|
230
|
-
mcpServers: {
|
|
231
|
-
posthog: mockServerConfig,
|
|
232
|
-
},
|
|
233
|
-
});
|
|
234
|
-
await client.addServer(mockApiKey);
|
|
235
|
-
const expectedConfigPath = path.join(mockHomeDir, '.cursor', 'mcp.json');
|
|
236
|
-
const expectedConfigDir = path.dirname(expectedConfigPath);
|
|
237
|
-
expect(mkdirMock).toHaveBeenCalledWith(expectedConfigDir, {
|
|
238
|
-
recursive: true,
|
|
239
|
-
});
|
|
240
|
-
expect(mergeMock).toHaveBeenCalledWith({}, { mcpServers: {} }, { mcpServers: { posthog: mockServerConfig } });
|
|
241
|
-
expect(writeFileMock).toHaveBeenCalledWith(expectedConfigPath, JSON.stringify({
|
|
242
|
-
mcpServers: {
|
|
243
|
-
posthog: mockServerConfig,
|
|
244
|
-
},
|
|
245
|
-
}, null, 2), 'utf8');
|
|
246
|
-
});
|
|
247
|
-
it('should merge with existing config when config file exists', async () => {
|
|
248
|
-
existsSyncMock.mockReturnValue(true);
|
|
249
|
-
const existingConfig = {
|
|
250
|
-
mcpServers: {
|
|
251
|
-
existingServer: {
|
|
252
|
-
command: 'existing',
|
|
253
|
-
args: [],
|
|
254
|
-
env: {},
|
|
255
|
-
},
|
|
256
|
-
},
|
|
257
|
-
};
|
|
258
|
-
readFileMock.mockResolvedValue(JSON.stringify(existingConfig));
|
|
259
|
-
mergeMock.mockReturnValue({
|
|
260
|
-
mcpServers: {
|
|
261
|
-
existingServer: existingConfig.mcpServers.existingServer,
|
|
262
|
-
posthog: mockServerConfig,
|
|
263
|
-
},
|
|
264
|
-
});
|
|
265
|
-
await client.addServer(mockApiKey);
|
|
266
|
-
expect(mergeMock).toHaveBeenCalledWith({}, existingConfig, {
|
|
267
|
-
mcpServers: { posthog: mockServerConfig },
|
|
268
|
-
});
|
|
269
|
-
expect(writeFileMock).toHaveBeenCalledWith(expect.any(String), JSON.stringify({
|
|
270
|
-
mcpServers: {
|
|
271
|
-
existingServer: existingConfig.mcpServers.existingServer,
|
|
272
|
-
posthog: mockServerConfig,
|
|
273
|
-
},
|
|
274
|
-
}, null, 2), 'utf8');
|
|
275
|
-
});
|
|
276
|
-
it('should create new config when existing config is invalid', async () => {
|
|
277
|
-
existsSyncMock.mockReturnValue(true);
|
|
278
|
-
readFileMock.mockResolvedValue('invalid json');
|
|
279
|
-
mergeMock.mockReturnValue({
|
|
280
|
-
mcpServers: {
|
|
281
|
-
posthog: mockServerConfig,
|
|
282
|
-
},
|
|
283
|
-
});
|
|
284
|
-
await client.addServer(mockApiKey);
|
|
285
|
-
expect(mergeMock).toHaveBeenCalledWith({}, { mcpServers: {} }, { mcpServers: { posthog: mockServerConfig } });
|
|
286
|
-
expect(writeFileMock).toHaveBeenCalledWith(expect.any(String), JSON.stringify({
|
|
287
|
-
mcpServers: {
|
|
288
|
-
posthog: mockServerConfig,
|
|
289
|
-
},
|
|
290
|
-
}, null, 2), 'utf8');
|
|
291
|
-
});
|
|
292
|
-
it('should handle mkdir failure gracefully', async () => {
|
|
293
|
-
existsSyncMock.mockReturnValue(false);
|
|
294
|
-
mkdirMock.mockRejectedValue(new Error('Permission denied'));
|
|
295
|
-
await expect(client.addServer(mockApiKey)).rejects.toThrow('Permission denied');
|
|
296
|
-
expect(writeFileMock).not.toHaveBeenCalled();
|
|
297
|
-
});
|
|
298
|
-
it('should handle writeFile failure gracefully', async () => {
|
|
299
|
-
existsSyncMock.mockReturnValue(false);
|
|
300
|
-
mkdirMock.mockResolvedValue(undefined); // Reset mkdir to succeed
|
|
301
|
-
mergeMock.mockReturnValue({ mcpServers: { posthog: mockServerConfig } });
|
|
302
|
-
writeFileMock.mockRejectedValue(new Error('Disk full'));
|
|
303
|
-
await expect(client.addServer(mockApiKey)).rejects.toThrow('Disk full');
|
|
304
|
-
});
|
|
305
|
-
it('should call getDefaultServerConfig with the provided API key', async () => {
|
|
306
|
-
existsSyncMock.mockReturnValue(false);
|
|
307
|
-
mergeMock.mockReturnValue({ mcpServers: { posthog: mockServerConfig } });
|
|
308
|
-
await client.addServer(mockApiKey);
|
|
309
|
-
expect(getDefaultServerConfigMock).toHaveBeenCalledWith(mockApiKey);
|
|
310
|
-
expect(getDefaultServerConfigMock).toHaveBeenCalledTimes(1);
|
|
311
|
-
});
|
|
312
|
-
it('should overwrite existing posthog server configuration', async () => {
|
|
313
|
-
existsSyncMock.mockReturnValue(true);
|
|
314
|
-
const existingConfig = {
|
|
315
|
-
mcpServers: {
|
|
316
|
-
posthog: {
|
|
317
|
-
command: 'old-command',
|
|
318
|
-
args: ['old-args'],
|
|
319
|
-
env: { OLD_ENV: 'old-value' },
|
|
320
|
-
},
|
|
321
|
-
otherServer: mockServerConfig,
|
|
322
|
-
},
|
|
323
|
-
};
|
|
324
|
-
readFileMock.mockResolvedValue(JSON.stringify(existingConfig));
|
|
325
|
-
mergeMock.mockReturnValue({
|
|
326
|
-
mcpServers: {
|
|
327
|
-
posthog: mockServerConfig,
|
|
328
|
-
otherServer: mockServerConfig,
|
|
329
|
-
},
|
|
330
|
-
});
|
|
331
|
-
await client.addServer(mockApiKey);
|
|
332
|
-
expect(mergeMock).toHaveBeenCalledWith({}, existingConfig, {
|
|
333
|
-
mcpServers: { posthog: mockServerConfig },
|
|
334
|
-
});
|
|
335
|
-
});
|
|
336
|
-
});
|
|
337
|
-
describe('removeServer', () => {
|
|
338
|
-
it('should do nothing when config file does not exist', async () => {
|
|
339
|
-
existsSyncMock.mockReturnValue(false);
|
|
340
|
-
await client.removeServer();
|
|
341
|
-
expect(readFileMock).not.toHaveBeenCalled();
|
|
342
|
-
expect(writeFileMock).not.toHaveBeenCalled();
|
|
343
|
-
});
|
|
344
|
-
it('should remove posthog server from config', async () => {
|
|
345
|
-
existsSyncMock.mockReturnValue(true);
|
|
346
|
-
const configWithPosthog = {
|
|
347
|
-
mcpServers: {
|
|
348
|
-
posthog: mockServerConfig,
|
|
349
|
-
otherServer: {
|
|
350
|
-
command: 'other',
|
|
351
|
-
args: [],
|
|
352
|
-
env: {},
|
|
353
|
-
},
|
|
354
|
-
},
|
|
355
|
-
};
|
|
356
|
-
readFileMock.mockResolvedValue(JSON.stringify(configWithPosthog));
|
|
357
|
-
await client.removeServer();
|
|
358
|
-
expect(writeFileMock).toHaveBeenCalledWith(expect.any(String), JSON.stringify({
|
|
359
|
-
mcpServers: {
|
|
360
|
-
otherServer: configWithPosthog.mcpServers.otherServer,
|
|
361
|
-
},
|
|
362
|
-
}, null, 2), 'utf8');
|
|
363
|
-
});
|
|
364
|
-
it('should handle config with only posthog server', async () => {
|
|
365
|
-
existsSyncMock.mockReturnValue(true);
|
|
366
|
-
const configWithOnlyPosthog = {
|
|
367
|
-
mcpServers: {
|
|
368
|
-
posthog: mockServerConfig,
|
|
369
|
-
},
|
|
370
|
-
};
|
|
371
|
-
readFileMock.mockResolvedValue(JSON.stringify(configWithOnlyPosthog));
|
|
372
|
-
await client.removeServer();
|
|
373
|
-
expect(writeFileMock).toHaveBeenCalledWith(expect.any(String), JSON.stringify({
|
|
374
|
-
mcpServers: {},
|
|
375
|
-
}, null, 2), 'utf8');
|
|
376
|
-
});
|
|
377
|
-
it('should do nothing when posthog server is not in config', async () => {
|
|
378
|
-
existsSyncMock.mockReturnValue(true);
|
|
379
|
-
const configWithoutPosthog = {
|
|
380
|
-
mcpServers: {
|
|
381
|
-
otherServer: {
|
|
382
|
-
command: 'other',
|
|
383
|
-
args: [],
|
|
384
|
-
env: {},
|
|
385
|
-
},
|
|
386
|
-
},
|
|
387
|
-
};
|
|
388
|
-
readFileMock.mockResolvedValue(JSON.stringify(configWithoutPosthog));
|
|
389
|
-
await client.removeServer();
|
|
390
|
-
expect(writeFileMock).not.toHaveBeenCalled();
|
|
391
|
-
});
|
|
392
|
-
it('should handle config with empty mcpServers', async () => {
|
|
393
|
-
existsSyncMock.mockReturnValue(true);
|
|
394
|
-
const configWithEmptyServers = {
|
|
395
|
-
mcpServers: {},
|
|
396
|
-
};
|
|
397
|
-
readFileMock.mockResolvedValue(JSON.stringify(configWithEmptyServers));
|
|
398
|
-
await client.removeServer();
|
|
399
|
-
expect(writeFileMock).not.toHaveBeenCalled();
|
|
400
|
-
});
|
|
401
|
-
it('should handle invalid JSON gracefully', async () => {
|
|
402
|
-
existsSyncMock.mockReturnValue(true);
|
|
403
|
-
readFileMock.mockResolvedValue('invalid json');
|
|
404
|
-
await client.removeServer();
|
|
405
|
-
expect(writeFileMock).not.toHaveBeenCalled();
|
|
406
|
-
});
|
|
407
|
-
it('should handle file read errors gracefully', async () => {
|
|
408
|
-
existsSyncMock.mockReturnValue(true);
|
|
409
|
-
readFileMock.mockRejectedValue(new Error('File read error'));
|
|
410
|
-
await client.removeServer();
|
|
411
|
-
expect(writeFileMock).not.toHaveBeenCalled();
|
|
412
|
-
});
|
|
413
|
-
it('should handle Zod parsing errors gracefully', async () => {
|
|
414
|
-
existsSyncMock.mockReturnValue(true);
|
|
415
|
-
readFileMock.mockResolvedValue(JSON.stringify({ valid: 'json' }));
|
|
416
|
-
const { DefaultMCPClientConfig } = require('../../defaults');
|
|
417
|
-
DefaultMCPClientConfig.parse.mockImplementation(() => {
|
|
418
|
-
throw new Error('Zod validation error');
|
|
419
|
-
});
|
|
420
|
-
await client.removeServer();
|
|
421
|
-
expect(writeFileMock).not.toHaveBeenCalled();
|
|
422
|
-
});
|
|
423
|
-
it('should handle writeFile errors gracefully', async () => {
|
|
424
|
-
existsSyncMock.mockReturnValue(true);
|
|
425
|
-
const configWithPosthog = {
|
|
426
|
-
mcpServers: {
|
|
427
|
-
posthog: mockServerConfig,
|
|
428
|
-
},
|
|
429
|
-
};
|
|
430
|
-
readFileMock.mockResolvedValue(JSON.stringify(configWithPosthog));
|
|
431
|
-
writeFileMock.mockRejectedValue(new Error('Disk full'));
|
|
432
|
-
await expect(client.removeServer()).rejects.toThrow('Disk full');
|
|
433
|
-
});
|
|
434
|
-
it('should handle config without mcpServers property', async () => {
|
|
435
|
-
existsSyncMock.mockReturnValue(true);
|
|
436
|
-
const configWithoutMcpServers = {};
|
|
437
|
-
readFileMock.mockResolvedValue(JSON.stringify(configWithoutMcpServers));
|
|
438
|
-
await client.removeServer();
|
|
439
|
-
expect(writeFileMock).not.toHaveBeenCalled();
|
|
440
|
-
});
|
|
441
|
-
});
|
|
442
|
-
});
|
|
443
|
-
//# sourceMappingURL=cursor.test.js.map
|