@clix-so/clix-agent-skills 0.1.5 → 0.1.7
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 +13 -13
- package/dist/bin/cli.js +1 -1
- package/dist/bin/commands/install.js +2 -0
- package/dist/bin/utils/mcp.js +63 -14
- package/llms.txt +6 -6
- package/package.json +1 -1
- package/skills/event-tracking/SKILL.md +3 -2
- package/skills/integration/SKILL.md +6 -5
- package/skills/integration/references/mcp-integration.md +0 -20
- package/skills/integration/scripts/install-mcp.sh +269 -34
- package/skills/user-management/SKILL.md +2 -2
package/README.md
CHANGED
|
@@ -16,9 +16,9 @@ you can install skills in different ways.
|
|
|
16
16
|
|
|
17
17
|
### Universal CLI (Recommended)
|
|
18
18
|
|
|
19
|
-
For **Cursor**, **VS Code**, **Claude
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
For **Cursor**, **VS Code**, **Claude Code**, **OpenCode**, **Goose**, **GitHub
|
|
20
|
+
Copilot**, **Amp**, and **Letta**, use our tool to install skills and configure
|
|
21
|
+
the Clix MCP Server automatically:
|
|
22
22
|
|
|
23
23
|
#### Installation Modes
|
|
24
24
|
|
|
@@ -66,16 +66,16 @@ npx @clix-so/clix-agent-skills@latest install --all --client cursor --global
|
|
|
66
66
|
|
|
67
67
|
**Supported Clients:**
|
|
68
68
|
|
|
69
|
-
| Client | Flag
|
|
70
|
-
| :------------- |
|
|
71
|
-
| Amp | `--client amp`
|
|
72
|
-
| Claude
|
|
73
|
-
| Codex | `--client codex`
|
|
74
|
-
| Cursor | `--client cursor`
|
|
75
|
-
| GitHub Copilot | `--client github`
|
|
76
|
-
| Goose | `--client goose`
|
|
77
|
-
| Letta | `--client letta`
|
|
78
|
-
| OpenCode | `--client opencode`
|
|
69
|
+
| Client | Flag | Default Path |
|
|
70
|
+
| :------------- | :----------------------------------- | :----------------- |
|
|
71
|
+
| Amp | `--client amp` | `.amp/skills/` |
|
|
72
|
+
| Claude Code | `--client claude` (or `claude-code`) | `.claude/skills/` |
|
|
73
|
+
| Codex | `--client codex` | `.codex/skills/` |
|
|
74
|
+
| Cursor | `--client cursor` | `.cursor/skills/` |
|
|
75
|
+
| GitHub Copilot | `--client github` | `.github/skills/` |
|
|
76
|
+
| Goose | `--client goose` | `.goose/skills/` |
|
|
77
|
+
| Letta | `--client letta` | `.skills/` |
|
|
78
|
+
| OpenCode | `--client opencode` | `.opencode/skill/` |
|
|
79
79
|
|
|
80
80
|
### Claude Code
|
|
81
81
|
|
package/dist/bin/cli.js
CHANGED
|
@@ -25,7 +25,7 @@ program
|
|
|
25
25
|
program
|
|
26
26
|
.command("install [skill]")
|
|
27
27
|
.description("Install agent skill(s)")
|
|
28
|
-
.option("-c, --client <client>", "Target AI client (cursor, claude, vscode, amp, kiro, amazonq, codex, opencode, manual)")
|
|
28
|
+
.option("-c, --client <client>", "Target AI client (cursor, claude|claude-code, vscode, amp, kiro, amazonq, codex, opencode, manual)")
|
|
29
29
|
.option("-p, --path <path>", "Custom installation path (default: .clix/skills)")
|
|
30
30
|
.option("-a, --all", "Install all available skills")
|
|
31
31
|
.option("-g, --global", "Install globally to system root (default: installs to repo root)")
|
|
@@ -64,6 +64,8 @@ async function installSkill(skillName, options) {
|
|
|
64
64
|
else if (options.client) {
|
|
65
65
|
switch (options.client.toLowerCase()) {
|
|
66
66
|
case "claude":
|
|
67
|
+
case "claude-code":
|
|
68
|
+
// Claude Code uses the .claude/ folder convention, but MCP is configured via `claude mcp ...`
|
|
67
69
|
relativeDest = ".claude/skills";
|
|
68
70
|
break;
|
|
69
71
|
case "cursor":
|
package/dist/bin/utils/mcp.js
CHANGED
|
@@ -43,6 +43,7 @@ const os_1 = __importDefault(require("os"));
|
|
|
43
43
|
const chalk_1 = __importDefault(require("chalk"));
|
|
44
44
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
45
45
|
const TOML = __importStar(require("@iarna/toml"));
|
|
46
|
+
const child_process_1 = require("child_process");
|
|
46
47
|
// ============================================================================
|
|
47
48
|
// Constants
|
|
48
49
|
// ============================================================================
|
|
@@ -50,6 +51,17 @@ const CLIX_MCP_SERVER_ENTRY = {
|
|
|
50
51
|
command: "npx",
|
|
51
52
|
args: ["-y", "@clix-so/clix-mcp-server@latest"],
|
|
52
53
|
};
|
|
54
|
+
const CLAUDE_CODE_MCP_ADD_ARGS = [
|
|
55
|
+
"mcp",
|
|
56
|
+
"add",
|
|
57
|
+
"--transport",
|
|
58
|
+
"stdio",
|
|
59
|
+
"clix-mcp-server",
|
|
60
|
+
"--",
|
|
61
|
+
"npx",
|
|
62
|
+
"-y",
|
|
63
|
+
"@clix-so/clix-mcp-server@latest",
|
|
64
|
+
];
|
|
53
65
|
// ============================================================================
|
|
54
66
|
// Helper Functions
|
|
55
67
|
// ============================================================================
|
|
@@ -62,6 +74,47 @@ function getErrorMessage(error) {
|
|
|
62
74
|
}
|
|
63
75
|
return String(error);
|
|
64
76
|
}
|
|
77
|
+
function hasClixServerInClaudeMcpListOutput(output) {
|
|
78
|
+
return output.toLowerCase().includes("clix-mcp-server");
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Configure MCP for Claude Code using the `claude` CLI (no config file editing).
|
|
82
|
+
*/
|
|
83
|
+
async function configureClaudeCode() {
|
|
84
|
+
console.log(chalk_1.default.blue("Checking MCP config via Claude Code CLI (`claude mcp`)..."));
|
|
85
|
+
// Verify Claude CLI exists and supports MCP.
|
|
86
|
+
const helpRes = (0, child_process_1.spawnSync)("claude", ["mcp", "--help"], { encoding: "utf8" });
|
|
87
|
+
if (helpRes.error) {
|
|
88
|
+
console.log(chalk_1.default.yellow(`Could not run Claude CLI (${getErrorMessage(helpRes.error)}). Skipping MCP configuration.`));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (helpRes.status !== 0) {
|
|
92
|
+
console.log(chalk_1.default.yellow("Claude CLI does not appear to support `claude mcp`. Skipping MCP configuration."));
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
// Best-effort idempotency: if list works and already contains the server, skip.
|
|
96
|
+
const listRes = (0, child_process_1.spawnSync)("claude", ["mcp", "list"], { encoding: "utf8" });
|
|
97
|
+
const listOut = `${listRes.stdout ?? ""}\n${listRes.stderr ?? ""}`;
|
|
98
|
+
if (!listRes.error && listRes.status === 0 && hasClixServerInClaudeMcpListOutput(listOut)) {
|
|
99
|
+
console.log(chalk_1.default.green("✔ Clix MCP Server is already configured."));
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const addRes = (0, child_process_1.spawnSync)("claude", CLAUDE_CODE_MCP_ADD_ARGS, { encoding: "utf8" });
|
|
103
|
+
if (addRes.error || addRes.status !== 0) {
|
|
104
|
+
const out = `${addRes.stdout ?? ""}\n${addRes.stderr ?? ""}`.trim();
|
|
105
|
+
console.log(chalk_1.default.yellow(`Failed to configure MCP via Claude Code CLI. ${out ? `Output:\n${out}` : "No output captured."}`));
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
console.log(chalk_1.default.green("✔ Added Clix MCP Server to configuration. Please restart claude."));
|
|
109
|
+
}
|
|
110
|
+
function isClaudeCodeClient(client) {
|
|
111
|
+
const c = client.toLowerCase();
|
|
112
|
+
return (c === "claude" ||
|
|
113
|
+
c === "claude_code" ||
|
|
114
|
+
c === "claude-code" ||
|
|
115
|
+
c === "claudecode" ||
|
|
116
|
+
c === "claude code");
|
|
117
|
+
}
|
|
65
118
|
/**
|
|
66
119
|
* Gets the MCP servers object from JSON config based on client type
|
|
67
120
|
*/
|
|
@@ -106,19 +159,6 @@ function getClientConfig(client) {
|
|
|
106
159
|
format: "json",
|
|
107
160
|
};
|
|
108
161
|
}
|
|
109
|
-
case "claude": {
|
|
110
|
-
let configPath = null;
|
|
111
|
-
if (process.platform === "darwin") {
|
|
112
|
-
configPath = path_1.default.join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
113
|
-
}
|
|
114
|
-
else if (process.platform === "win32") {
|
|
115
|
-
configPath = path_1.default.join(process.env.APPDATA || "", "Claude", "claude_desktop_config.json");
|
|
116
|
-
}
|
|
117
|
-
else if (process.platform === "linux") {
|
|
118
|
-
configPath = path_1.default.join(home, ".config", "Claude", "claude_desktop_config.json");
|
|
119
|
-
}
|
|
120
|
-
return configPath ? { path: configPath, configKey: "mcpServers", format: "json" } : null;
|
|
121
|
-
}
|
|
122
162
|
case "vscode":
|
|
123
163
|
return {
|
|
124
164
|
path: path_1.default.join(home, ".vscode", "mcp.json"),
|
|
@@ -306,7 +346,7 @@ async function configureMCP(client) {
|
|
|
306
346
|
message: "Which AI client are you using?",
|
|
307
347
|
choices: [
|
|
308
348
|
{ name: "Cursor", value: "cursor" },
|
|
309
|
-
{ name: "Claude
|
|
349
|
+
{ name: "Claude Code", value: "claude" },
|
|
310
350
|
{ name: "VS Code", value: "vscode" },
|
|
311
351
|
{ name: "Amp", value: "amp" },
|
|
312
352
|
{ name: "Kiro", value: "kiro" },
|
|
@@ -322,10 +362,19 @@ async function configureMCP(client) {
|
|
|
322
362
|
]);
|
|
323
363
|
targetClient = answers.client;
|
|
324
364
|
}
|
|
365
|
+
if (!targetClient) {
|
|
366
|
+
console.log(chalk_1.default.yellow("No client selected. Skipping MCP configuration."));
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
325
369
|
if (targetClient === "manual") {
|
|
326
370
|
console.log(chalk_1.default.blue("Skipping automatic MCP configuration."));
|
|
327
371
|
return;
|
|
328
372
|
}
|
|
373
|
+
// Claude Code is configured via the `claude` CLI (no file editing).
|
|
374
|
+
if (targetClient && isClaudeCodeClient(targetClient)) {
|
|
375
|
+
await configureClaudeCode();
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
329
378
|
// Handle OpenCode separately (different JSON structure)
|
|
330
379
|
if (targetClient === "opencode") {
|
|
331
380
|
await configureOpenCode();
|
package/llms.txt
CHANGED
|
@@ -9,9 +9,9 @@ Each entry includes the file path, type, and description for semantic search.
|
|
|
9
9
|
|
|
10
10
|
## clix-event-tracking
|
|
11
11
|
|
|
12
|
-
Implements Clix event tracking (Clix.trackEvent) with consistent naming, safe property schemas, and campaign-ready validation. Use when adding, reviewing, or debugging event tracking; when configuring event-triggered campaigns; or when the user mentions events, tracking, funnels, or properties
|
|
12
|
+
Implements Clix event tracking (Clix.trackEvent) with consistent naming, safe property schemas, and campaign-ready validation. Use when adding, reviewing, or debugging event tracking; when configuring event-triggered campaigns; or when the user mentions events, tracking, funnels, or properties — or when the user types `clix-event-tracking`.
|
|
13
13
|
|
|
14
|
-
- [clix-event-tracking](https://raw.githubusercontent.com/clix-so/skills/refs/heads/main/skills/event-tracking/SKILL.md): Implements Clix event tracking (Clix.trackEvent) with consistent naming, safe property schemas, and campaign-ready validation. Use when adding, reviewing, or debugging event tracking; when configuring event-triggered campaigns; or when the user mentions events, tracking, funnels, or properties
|
|
14
|
+
- [clix-event-tracking](https://raw.githubusercontent.com/clix-so/skills/refs/heads/main/skills/event-tracking/SKILL.md): Implements Clix event tracking (Clix.trackEvent) with consistent naming, safe property schemas, and campaign-ready validation. Use when adding, reviewing, or debugging event tracking; when configuring event-triggered campaigns; or when the user mentions events, tracking, funnels, or properties — or when the user types `clix-event-tracking`.
|
|
15
15
|
|
|
16
16
|
### References
|
|
17
17
|
|
|
@@ -29,9 +29,9 @@ Implements Clix event tracking (Clix.trackEvent) with consistent naming, safe pr
|
|
|
29
29
|
|
|
30
30
|
## clix-integration
|
|
31
31
|
|
|
32
|
-
Integrates Clix Mobile SDK into iOS, Android, Flutter, and React Native projects. Provides step-by-step guidance for installation, initialization, and verification. Use when the user asks to install, setup, or
|
|
32
|
+
Integrates Clix Mobile SDK into iOS, Android, Flutter, and React Native projects. Provides step-by-step guidance for installation, initialization, and verification. Use when the user asks to install, setup, integrate Clix or when the user types `clix-integration` / "clix integration".
|
|
33
33
|
|
|
34
|
-
- [clix-integration](https://raw.githubusercontent.com/clix-so/skills/refs/heads/main/skills/integration/SKILL.md): Integrates Clix Mobile SDK into iOS, Android, Flutter, and React Native projects. Provides step-by-step guidance for installation, initialization, and verification. Use when the user asks to install, setup, or
|
|
34
|
+
- [clix-integration](https://raw.githubusercontent.com/clix-so/skills/refs/heads/main/skills/integration/SKILL.md): Integrates Clix Mobile SDK into iOS, Android, Flutter, and React Native projects. Provides step-by-step guidance for installation, initialization, and verification. Use when the user asks to install, setup, integrate Clix or when the user types `clix-integration` / "clix integration".
|
|
35
35
|
|
|
36
36
|
### References
|
|
37
37
|
|
|
@@ -56,9 +56,9 @@ Integrates Clix Mobile SDK into iOS, Android, Flutter, and React Native projects
|
|
|
56
56
|
|
|
57
57
|
## clix-user-management
|
|
58
58
|
|
|
59
|
-
Implements Clix user identification and user properties (setUserId, removeUserId, setUserProperty/setUserProperties, removeUserProperty/removeUserProperties) with safe schemas, logout best practices, and campaign-ready personalization/audience usage. Use when the user mentions login/logout, userId, user properties, personalization, or
|
|
59
|
+
Implements Clix user identification and user properties (setUserId, removeUserId, setUserProperty/setUserProperties, removeUserProperty/removeUserProperties) with safe schemas, logout best practices, and campaign-ready personalization/audience usage. Use when the user mentions login/logout, userId, user properties, personalization, audience targeting or when the user types `clix-user-management`.
|
|
60
60
|
|
|
61
|
-
- [clix-user-management](https://raw.githubusercontent.com/clix-so/skills/refs/heads/main/skills/user-management/SKILL.md): Implements Clix user identification and user properties (setUserId, removeUserId, setUserProperty/setUserProperties, removeUserProperty/removeUserProperties) with safe schemas, logout best practices, and campaign-ready personalization/audience usage. Use when the user mentions login/logout, userId, user properties, personalization, or
|
|
61
|
+
- [clix-user-management](https://raw.githubusercontent.com/clix-so/skills/refs/heads/main/skills/user-management/SKILL.md): Implements Clix user identification and user properties (setUserId, removeUserId, setUserProperty/setUserProperties, removeUserProperty/removeUserProperties) with safe schemas, logout best practices, and campaign-ready personalization/audience usage. Use when the user mentions login/logout, userId, user properties, personalization, audience targeting or when the user types `clix-user-management`.
|
|
62
62
|
|
|
63
63
|
### References
|
|
64
64
|
|
package/package.json
CHANGED
|
@@ -4,7 +4,8 @@ description:
|
|
|
4
4
|
Implements Clix event tracking (Clix.trackEvent) with consistent naming, safe
|
|
5
5
|
property schemas, and campaign-ready validation. Use when adding, reviewing,
|
|
6
6
|
or debugging event tracking; when configuring event-triggered campaigns; or
|
|
7
|
-
when the user mentions events, tracking, funnels, or properties
|
|
7
|
+
when the user mentions events, tracking, funnels, or properties — or when the
|
|
8
|
+
user types `clix-event-tracking`.
|
|
8
9
|
---
|
|
9
10
|
|
|
10
11
|
# Tracking Clix Events
|
|
@@ -96,7 +97,7 @@ bash <skill-dir>/scripts/validate-event-plan.sh event-plan.json
|
|
|
96
97
|
The skill directory is typically:
|
|
97
98
|
|
|
98
99
|
- `.cursor/skills/event-tracking/` (Cursor)
|
|
99
|
-
- `.claude/skills/event-tracking/` (Claude
|
|
100
|
+
- `.claude/skills/event-tracking/` (Claude Code)
|
|
100
101
|
- `.vscode/skills/event-tracking/` (VS Code/Amp)
|
|
101
102
|
- Or check where this skill was installed
|
|
102
103
|
|
|
@@ -3,8 +3,8 @@ name: clix-integration
|
|
|
3
3
|
description:
|
|
4
4
|
Integrates Clix Mobile SDK into iOS, Android, Flutter, and React Native
|
|
5
5
|
projects. Provides step-by-step guidance for installation, initialization, and
|
|
6
|
-
verification. Use when the user asks to install, setup, or
|
|
7
|
-
|
|
6
|
+
verification. Use when the user asks to install, setup, integrate Clix or when
|
|
7
|
+
the user types `clix-integration` / "clix integration".
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# Clix SDK Integration Skill
|
|
@@ -38,11 +38,12 @@ latest verified SDK source code.
|
|
|
38
38
|
1. **Ask the user**: "The Clix MCP Server is not detected. It provides the
|
|
39
39
|
latest official SDK code. Would you like me to install it now?"
|
|
40
40
|
2. **If User says YES**:
|
|
41
|
-
- Run: `bash scripts/install-mcp.sh
|
|
41
|
+
- Run: `bash scripts/install-mcp.sh --client <your-client>`
|
|
42
42
|
- The script will:
|
|
43
43
|
- Verify the package is available
|
|
44
|
-
-
|
|
45
|
-
|
|
44
|
+
- Configure the MCP server for the specified client
|
|
45
|
+
- (If you omit `--client` and multiple clients are installed, the script
|
|
46
|
+
will stop and ask you to choose.)
|
|
46
47
|
- Automatically configure the MCP server in the appropriate config file
|
|
47
48
|
- Provide clear instructions for restart
|
|
48
49
|
- Instruct user to restart their agent/IDE to load the new server.
|
|
@@ -263,26 +263,6 @@ claude mcp add --transport stdio clix-mcp-server -- npx -y @clix-so/clix-mcp-ser
|
|
|
263
263
|
}
|
|
264
264
|
```
|
|
265
265
|
|
|
266
|
-
#### Claude Desktop App
|
|
267
|
-
|
|
268
|
-
**Setup**
|
|
269
|
-
|
|
270
|
-
1. Open config
|
|
271
|
-
(`~/Library/Application Support/Claude/claude_desktop_config.json` or
|
|
272
|
-
`%APPDATA%\\Claude\\claude_desktop_config.json`).
|
|
273
|
-
2. Add and restart:
|
|
274
|
-
|
|
275
|
-
```json
|
|
276
|
-
{
|
|
277
|
-
"mcpServers": {
|
|
278
|
-
"clix-mcp-server": {
|
|
279
|
-
"command": "npx",
|
|
280
|
-
"args": ["-y", "@clix-so/clix-mcp-server@latest"]
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
```
|
|
285
|
-
|
|
286
266
|
#### Amp
|
|
287
267
|
|
|
288
268
|
**Setup**
|
|
@@ -18,6 +18,64 @@ log() {
|
|
|
18
18
|
printf "%b\n" "$1"
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
log_err() {
|
|
22
|
+
printf "%b\n" "$1" >&2
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
usage() {
|
|
26
|
+
cat <<'EOF'
|
|
27
|
+
Clix MCP Server Installer
|
|
28
|
+
|
|
29
|
+
Usage:
|
|
30
|
+
bash scripts/install-mcp.sh [--client <client>]
|
|
31
|
+
|
|
32
|
+
Options:
|
|
33
|
+
--client <client> Explicitly select the MCP client to configure.
|
|
34
|
+
Supported: claude, claude-code, opencode, amp, codex, cursor, vscode
|
|
35
|
+
--help Show this help.
|
|
36
|
+
|
|
37
|
+
Environment:
|
|
38
|
+
CLIX_MCP_CLIENT Same as --client (takes precedence).
|
|
39
|
+
|
|
40
|
+
Notes:
|
|
41
|
+
If multiple MCP clients are detected on this machine, you MUST pass --client
|
|
42
|
+
(or set CLIX_MCP_CLIENT). A shell script cannot reliably know "which client is
|
|
43
|
+
currently running" on a machine with multiple clients installed.
|
|
44
|
+
EOF
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# Parse args/env
|
|
48
|
+
CLIENT_OVERRIDE="${CLIX_MCP_CLIENT:-}"
|
|
49
|
+
while [ $# -gt 0 ]; do
|
|
50
|
+
case "$1" in
|
|
51
|
+
--help|-h)
|
|
52
|
+
usage
|
|
53
|
+
exit 0
|
|
54
|
+
;;
|
|
55
|
+
--client)
|
|
56
|
+
shift
|
|
57
|
+
CLIENT_OVERRIDE="${1:-}"
|
|
58
|
+
;;
|
|
59
|
+
--client=*)
|
|
60
|
+
CLIENT_OVERRIDE="${1#*=}"
|
|
61
|
+
;;
|
|
62
|
+
*)
|
|
63
|
+
log_err "${YELLOW}⚠️ Unknown argument: $1${RESET}"
|
|
64
|
+
usage
|
|
65
|
+
exit 2
|
|
66
|
+
;;
|
|
67
|
+
esac
|
|
68
|
+
shift || true
|
|
69
|
+
done
|
|
70
|
+
|
|
71
|
+
validate_client() {
|
|
72
|
+
case "${1:-}" in
|
|
73
|
+
claude|claude-code|opencode|amp|codex|cursor|vscode) return 0 ;;
|
|
74
|
+
"") return 1 ;;
|
|
75
|
+
*) return 1 ;;
|
|
76
|
+
esac
|
|
77
|
+
}
|
|
78
|
+
|
|
21
79
|
# Detect platform
|
|
22
80
|
detect_platform() {
|
|
23
81
|
case "$(uname -s)" in
|
|
@@ -35,6 +93,10 @@ get_config_path() {
|
|
|
35
93
|
local platform=$(detect_platform)
|
|
36
94
|
|
|
37
95
|
case "$client" in
|
|
96
|
+
claude-code)
|
|
97
|
+
# Claude Code CLI manages MCP via `claude mcp ...` commands (no direct config file here)
|
|
98
|
+
echo ""
|
|
99
|
+
;;
|
|
38
100
|
codex)
|
|
39
101
|
echo "${home}/.codex/config.toml"
|
|
40
102
|
;;
|
|
@@ -47,13 +109,8 @@ get_config_path() {
|
|
|
47
109
|
fi
|
|
48
110
|
;;
|
|
49
111
|
claude)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
elif [ "$platform" = "win32" ]; then
|
|
53
|
-
echo "${APPDATA:-}/Claude/claude_desktop_config.json"
|
|
54
|
-
else
|
|
55
|
-
echo "${home}/.config/claude/claude_desktop_config.json"
|
|
56
|
-
fi
|
|
112
|
+
# Alias for Claude Code
|
|
113
|
+
echo ""
|
|
57
114
|
;;
|
|
58
115
|
vscode)
|
|
59
116
|
echo "${home}/.vscode/mcp.json"
|
|
@@ -88,6 +145,25 @@ get_config_path() {
|
|
|
88
145
|
esac
|
|
89
146
|
}
|
|
90
147
|
|
|
148
|
+
# Configure MCP for Claude Code CLI
|
|
149
|
+
configure_claude_code() {
|
|
150
|
+
if ! command -v claude &> /dev/null; then
|
|
151
|
+
log "${RED}❌ Claude CLI not found on PATH.${RESET}"
|
|
152
|
+
exit 1
|
|
153
|
+
fi
|
|
154
|
+
|
|
155
|
+
# Best-effort: avoid failing if already configured.
|
|
156
|
+
# If list isn't supported, we'll just attempt add.
|
|
157
|
+
if claude mcp list 2>/dev/null | grep -q "clix-mcp-server"; then
|
|
158
|
+
log "${GREEN}✔ Clix MCP Server already configured in Claude Code${RESET}"
|
|
159
|
+
return 0
|
|
160
|
+
fi
|
|
161
|
+
|
|
162
|
+
# Configure via CLI (non-interactive)
|
|
163
|
+
claude mcp add --transport stdio clix-mcp-server -- npx -y @clix-so/clix-mcp-server@latest
|
|
164
|
+
log "${GREEN}✔ Configured Clix MCP Server in Claude Code${RESET}"
|
|
165
|
+
}
|
|
166
|
+
|
|
91
167
|
# Configure MCP for Codex (TOML format)
|
|
92
168
|
configure_codex() {
|
|
93
169
|
local config_path="$1"
|
|
@@ -158,7 +234,7 @@ configure_amp() {
|
|
|
158
234
|
return 0
|
|
159
235
|
fi
|
|
160
236
|
|
|
161
|
-
# Use node to safely update JSON
|
|
237
|
+
# Use node to safely update JSON/JSONC (VS Code settings often allow comments)
|
|
162
238
|
if command -v node &> /dev/null; then
|
|
163
239
|
node <<EOF
|
|
164
240
|
const fs = require('fs');
|
|
@@ -166,7 +242,61 @@ const path = '$config_path';
|
|
|
166
242
|
let config = {};
|
|
167
243
|
try {
|
|
168
244
|
const content = fs.readFileSync(path, 'utf8');
|
|
169
|
-
|
|
245
|
+
const stripJsonc = (input) => {
|
|
246
|
+
// Strips // and /* */ comments, but preserves anything inside strings.
|
|
247
|
+
let out = '';
|
|
248
|
+
let inStr = false;
|
|
249
|
+
let esc = false;
|
|
250
|
+
let inLine = false;
|
|
251
|
+
let inBlock = false;
|
|
252
|
+
for (let i = 0; i < input.length; i++) {
|
|
253
|
+
const c = input[i];
|
|
254
|
+
const n = input[i + 1];
|
|
255
|
+
if (inLine) {
|
|
256
|
+
if (c === '\n') {
|
|
257
|
+
inLine = false;
|
|
258
|
+
out += c;
|
|
259
|
+
}
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
if (inBlock) {
|
|
263
|
+
if (c === '*' && n === '/') {
|
|
264
|
+
inBlock = false;
|
|
265
|
+
i++;
|
|
266
|
+
}
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
if (inStr) {
|
|
270
|
+
out += c;
|
|
271
|
+
if (esc) {
|
|
272
|
+
esc = false;
|
|
273
|
+
} else if (c === '\\\\') {
|
|
274
|
+
esc = true;
|
|
275
|
+
} else if (c === '"') {
|
|
276
|
+
inStr = false;
|
|
277
|
+
}
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
if (c === '"') {
|
|
281
|
+
inStr = true;
|
|
282
|
+
out += c;
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
if (c === '/' && n === '/') {
|
|
286
|
+
inLine = true;
|
|
287
|
+
i++;
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
if (c === '/' && n === '*') {
|
|
291
|
+
inBlock = true;
|
|
292
|
+
i++;
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
out += c;
|
|
296
|
+
}
|
|
297
|
+
return out;
|
|
298
|
+
};
|
|
299
|
+
config = JSON.parse(stripJsonc(content));
|
|
170
300
|
} catch (e) {
|
|
171
301
|
config = {};
|
|
172
302
|
}
|
|
@@ -218,17 +348,72 @@ EOF
|
|
|
218
348
|
const fs = require('fs');
|
|
219
349
|
const path = '$config_path';
|
|
220
350
|
let content = fs.readFileSync(path, 'utf8');
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
let
|
|
351
|
+
const stripJsonc = (input) => {
|
|
352
|
+
// Strips // and /* */ comments, but preserves anything inside strings.
|
|
353
|
+
let out = '';
|
|
354
|
+
let inStr = false;
|
|
355
|
+
let esc = false;
|
|
356
|
+
let inLine = false;
|
|
357
|
+
let inBlock = false;
|
|
358
|
+
for (let i = 0; i < input.length; i++) {
|
|
359
|
+
const c = input[i];
|
|
360
|
+
const n = input[i + 1];
|
|
361
|
+
if (inLine) {
|
|
362
|
+
if (c === '\n') {
|
|
363
|
+
inLine = false;
|
|
364
|
+
out += c;
|
|
365
|
+
}
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
if (inBlock) {
|
|
369
|
+
if (c === '*' && n === '/') {
|
|
370
|
+
inBlock = false;
|
|
371
|
+
i++;
|
|
372
|
+
}
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
if (inStr) {
|
|
376
|
+
out += c;
|
|
377
|
+
if (esc) {
|
|
378
|
+
esc = false;
|
|
379
|
+
} else if (c === '\\\\') {
|
|
380
|
+
esc = true;
|
|
381
|
+
} else if (c === '"') {
|
|
382
|
+
inStr = false;
|
|
383
|
+
}
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
if (c === '"') {
|
|
387
|
+
inStr = true;
|
|
388
|
+
out += c;
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
if (c === '/' && n === '/') {
|
|
392
|
+
inLine = true;
|
|
393
|
+
i++;
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
if (c === '/' && n === '*') {
|
|
397
|
+
inBlock = true;
|
|
398
|
+
i++;
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
out += c;
|
|
402
|
+
}
|
|
403
|
+
return out;
|
|
404
|
+
};
|
|
405
|
+
let config = {};
|
|
406
|
+
try {
|
|
407
|
+
config = JSON.parse(stripJsonc(content));
|
|
408
|
+
} catch (e) {
|
|
409
|
+
config = {};
|
|
410
|
+
}
|
|
224
411
|
if (!config.mcp) config.mcp = {};
|
|
225
412
|
config.mcp['clix-mcp-server'] = {
|
|
226
413
|
type: 'local',
|
|
227
414
|
command: ['npx', '-y', '@clix-so/clix-mcp-server@latest'],
|
|
228
415
|
enabled: true
|
|
229
416
|
};
|
|
230
|
-
// Write back as JSONC if original was .jsonc, otherwise JSON
|
|
231
|
-
const isJsonc = path.endsWith('.jsonc');
|
|
232
417
|
fs.writeFileSync(path, JSON.stringify(config, null, 2) + '\n');
|
|
233
418
|
EOF
|
|
234
419
|
log "${GREEN}✔ Configured Clix MCP Server in OpenCode${RESET}"
|
|
@@ -291,48 +476,93 @@ EOF
|
|
|
291
476
|
fi
|
|
292
477
|
}
|
|
293
478
|
|
|
294
|
-
#
|
|
295
|
-
|
|
296
|
-
#
|
|
479
|
+
# Detect all matching clients (heuristics). Output one per line.
|
|
480
|
+
detect_clients() {
|
|
481
|
+
# Claude Code CLI (supports `claude mcp ...`)
|
|
482
|
+
if command -v claude &> /dev/null && claude mcp --help &> /dev/null; then
|
|
483
|
+
echo "claude"
|
|
484
|
+
fi
|
|
485
|
+
|
|
486
|
+
# OpenCode (project config files or opencode command)
|
|
297
487
|
if [ -f "opencode.json" ] || [ -f "opencode.jsonc" ] || command -v opencode &> /dev/null; then
|
|
298
488
|
echo "opencode"
|
|
299
|
-
return
|
|
300
489
|
fi
|
|
301
490
|
|
|
302
|
-
#
|
|
491
|
+
# Amp (amp command or amp.mcpServers present)
|
|
303
492
|
if command -v amp &> /dev/null || \
|
|
304
493
|
grep -q "amp.mcpServers" ".vscode/settings.json" 2>/dev/null || \
|
|
305
494
|
grep -q "amp.mcpServers" "${HOME}/.vscode/settings.json" 2>/dev/null; then
|
|
306
495
|
echo "amp"
|
|
307
|
-
return
|
|
308
496
|
fi
|
|
309
497
|
|
|
310
|
-
#
|
|
498
|
+
# Codex
|
|
311
499
|
if [ -f "${HOME}/.codex/config.toml" ] || command -v codex &> /dev/null; then
|
|
312
500
|
echo "codex"
|
|
313
|
-
return
|
|
314
501
|
fi
|
|
315
502
|
|
|
316
|
-
#
|
|
503
|
+
# Cursor
|
|
317
504
|
if [ -f "${HOME}/.cursor/mcp.json" ] || [ -f ".cursor/mcp.json" ]; then
|
|
318
505
|
echo "cursor"
|
|
506
|
+
fi
|
|
507
|
+
|
|
508
|
+
# VS Code
|
|
509
|
+
if [ -f "${HOME}/.vscode/mcp.json" ]; then
|
|
510
|
+
echo "vscode"
|
|
511
|
+
fi
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
choose_client() {
|
|
515
|
+
if [ -n "${CLIENT_OVERRIDE:-}" ]; then
|
|
516
|
+
if ! validate_client "$CLIENT_OVERRIDE"; then
|
|
517
|
+
log_err "${RED}❌ Invalid --client / CLIX_MCP_CLIENT: ${CLIENT_OVERRIDE}${RESET}"
|
|
518
|
+
usage
|
|
519
|
+
exit 2
|
|
520
|
+
fi
|
|
521
|
+
if [ "$CLIENT_OVERRIDE" = "claude-code" ]; then
|
|
522
|
+
echo "claude"
|
|
523
|
+
return
|
|
524
|
+
fi
|
|
525
|
+
echo "$CLIENT_OVERRIDE"
|
|
319
526
|
return
|
|
320
527
|
fi
|
|
321
528
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
529
|
+
local detected
|
|
530
|
+
detected="$(detect_clients | awk 'NF' | sort -u)"
|
|
531
|
+
local count
|
|
532
|
+
count="$(printf "%s\n" "$detected" | awk 'NF' | wc -l | tr -d ' ')"
|
|
533
|
+
|
|
534
|
+
if [ "${count:-0}" -eq 0 ]; then
|
|
535
|
+
echo "unknown"
|
|
326
536
|
return
|
|
327
537
|
fi
|
|
328
538
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
echo "vscode"
|
|
539
|
+
if [ "${count:-0}" -eq 1 ]; then
|
|
540
|
+
printf "%s\n" "$detected"
|
|
332
541
|
return
|
|
333
542
|
fi
|
|
334
543
|
|
|
335
|
-
|
|
544
|
+
# Multiple detected: we can't know which one is "currently running".
|
|
545
|
+
log_err "${YELLOW}⚠️ Multiple MCP clients detected on this machine:${RESET}"
|
|
546
|
+
printf "%s\n" "$detected" | sed 's/^/ - /' >&2
|
|
547
|
+
|
|
548
|
+
if [ -t 0 ]; then
|
|
549
|
+
log_err "${BLUE}Select which client to configure:${RESET}"
|
|
550
|
+
local options=()
|
|
551
|
+
while IFS= read -r line; do options+=("$line"); done <<<"$detected"
|
|
552
|
+
options+=("cancel")
|
|
553
|
+
select opt in "${options[@]}"; do
|
|
554
|
+
if [ "$opt" = "cancel" ] || [ -z "${opt:-}" ]; then
|
|
555
|
+
log_err "${YELLOW}Cancelled.${RESET}"
|
|
556
|
+
exit 2
|
|
557
|
+
fi
|
|
558
|
+
echo "$opt"
|
|
559
|
+
return
|
|
560
|
+
done
|
|
561
|
+
fi
|
|
562
|
+
|
|
563
|
+
log_err "${RED}❌ Ambiguous MCP client selection in non-interactive mode.${RESET}"
|
|
564
|
+
log_err "${YELLOW}Please re-run with: bash scripts/install-mcp.sh --client <client>${RESET}"
|
|
565
|
+
exit 2
|
|
336
566
|
}
|
|
337
567
|
|
|
338
568
|
log "${BLUE}📦 Installing Clix MCP Server...${RESET}"
|
|
@@ -355,13 +585,18 @@ fi
|
|
|
355
585
|
|
|
356
586
|
# Auto-detect and configure
|
|
357
587
|
log "${BLUE}🔍 Detecting MCP client...${RESET}"
|
|
358
|
-
detected_client=$(
|
|
588
|
+
detected_client=$(choose_client)
|
|
359
589
|
|
|
360
590
|
if [ "$detected_client" != "unknown" ]; then
|
|
361
591
|
log "${GREEN}Detected: $detected_client${RESET}"
|
|
362
592
|
config_path=$(get_config_path "$detected_client")
|
|
363
593
|
|
|
364
|
-
if [
|
|
594
|
+
if [ "$detected_client" = "claude" ]; then
|
|
595
|
+
log "${BLUE}Configuring MCP server for Claude Code...${RESET}"
|
|
596
|
+
configure_claude_code
|
|
597
|
+
log "${GREEN}✅ Successfully configured Clix MCP Server!${RESET}"
|
|
598
|
+
log "${YELLOW}⚠️ IMPORTANT: Please RESTART Claude Code for the changes to take effect.${RESET}"
|
|
599
|
+
elif [ -n "$config_path" ]; then
|
|
365
600
|
log "${BLUE}Configuring MCP server for $detected_client...${RESET}"
|
|
366
601
|
|
|
367
602
|
if [ "$detected_client" = "codex" ]; then
|
|
@@ -387,7 +622,7 @@ else
|
|
|
387
622
|
log "${BLUE} - Amp: Add to .vscode/settings.json or ~/.vscode/settings.json${RESET}"
|
|
388
623
|
log "${BLUE} - Codex: Add to ~/.codex/config.toml${RESET}"
|
|
389
624
|
log "${BLUE} - Cursor: Add to .cursor/mcp.json or ~/.cursor/mcp.json${RESET}"
|
|
390
|
-
log "${BLUE} - Claude
|
|
625
|
+
log "${BLUE} - Claude Code: Run: claude mcp add --transport stdio clix-mcp-server -- npx -y @clix-so/clix-mcp-server@latest${RESET}"
|
|
391
626
|
log "${BLUE}See references/mcp-integration.md for detailed instructions.${RESET}"
|
|
392
627
|
fi
|
|
393
628
|
|
|
@@ -5,8 +5,8 @@ description:
|
|
|
5
5
|
removeUserId, setUserProperty/setUserProperties,
|
|
6
6
|
removeUserProperty/removeUserProperties) with safe schemas, logout best
|
|
7
7
|
practices, and campaign-ready personalization/audience usage. Use when the
|
|
8
|
-
user mentions login/logout, userId, user properties, personalization,
|
|
9
|
-
|
|
8
|
+
user mentions login/logout, userId, user properties, personalization, audience
|
|
9
|
+
targeting or when the user types `clix-user-management`.
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# Clix User Management
|