perceptia-mcp 1.0.0 → 1.2.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/dist/cli.js +11 -5
- package/dist/setup.js +78 -5
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -4,15 +4,21 @@ import { runSetup } from "./setup.js";
|
|
|
4
4
|
const args = process.argv.slice(2);
|
|
5
5
|
const command = args[0];
|
|
6
6
|
if (command === "setup") {
|
|
7
|
-
|
|
7
|
+
let apiKey = args[1];
|
|
8
8
|
if (!apiKey) {
|
|
9
|
+
const { createInterface } = await import("node:readline");
|
|
10
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
11
|
+
const ask = (q) => new Promise((res) => rl.question(q, res));
|
|
9
12
|
console.log("Perceptia MCP — Setup");
|
|
10
13
|
console.log("");
|
|
11
|
-
console.log("
|
|
14
|
+
console.log("Get your API key at https://perceptiamcp.com/dashboard");
|
|
12
15
|
console.log("");
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
apiKey = (await ask("API Key (ck_live_...): ")).trim();
|
|
17
|
+
rl.close();
|
|
18
|
+
if (!apiKey) {
|
|
19
|
+
console.error("No API key provided. Exiting.");
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
16
22
|
}
|
|
17
23
|
await runSetup(apiKey);
|
|
18
24
|
}
|
package/dist/setup.js
CHANGED
|
@@ -14,12 +14,12 @@ function getClients() {
|
|
|
14
14
|
? path.join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json")
|
|
15
15
|
: path.join(home, ".config", "Claude", "claude_desktop_config.json");
|
|
16
16
|
if (fs.existsSync(path.dirname(claudeDesktopPath))) {
|
|
17
|
-
clients.push({ name: "Claude Desktop", configPath: claudeDesktopPath });
|
|
17
|
+
clients.push({ name: "Claude Desktop", configPath: claudeDesktopPath, type: "claude-desktop" });
|
|
18
18
|
}
|
|
19
19
|
// Claude Code
|
|
20
20
|
const claudeCodePath = path.join(home, ".claude", "settings.json");
|
|
21
21
|
if (fs.existsSync(path.dirname(claudeCodePath))) {
|
|
22
|
-
clients.push({ name: "Claude Code", configPath: claudeCodePath });
|
|
22
|
+
clients.push({ name: "Claude Code", configPath: claudeCodePath, type: "claude-code" });
|
|
23
23
|
}
|
|
24
24
|
// Cursor
|
|
25
25
|
const cursorPath = isWin
|
|
@@ -28,7 +28,7 @@ function getClients() {
|
|
|
28
28
|
? path.join(home, "Library", "Application Support", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json")
|
|
29
29
|
: path.join(home, ".config", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
|
|
30
30
|
if (fs.existsSync(path.dirname(cursorPath))) {
|
|
31
|
-
clients.push({ name: "Cursor", configPath: cursorPath });
|
|
31
|
+
clients.push({ name: "Cursor", configPath: cursorPath, type: "cursor" });
|
|
32
32
|
}
|
|
33
33
|
return clients;
|
|
34
34
|
}
|
|
@@ -58,6 +58,75 @@ function writeConfig(configPath, apiKey) {
|
|
|
58
58
|
};
|
|
59
59
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
60
60
|
}
|
|
61
|
+
function setupHook(configPath, apiKey) {
|
|
62
|
+
const dir = path.dirname(configPath);
|
|
63
|
+
if (!fs.existsSync(dir)) {
|
|
64
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
65
|
+
}
|
|
66
|
+
let config = {};
|
|
67
|
+
if (fs.existsSync(configPath)) {
|
|
68
|
+
try {
|
|
69
|
+
config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
config = {};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const isWin = process.platform === "win32";
|
|
76
|
+
const hooksDir = path.join(path.dirname(configPath), "hooks");
|
|
77
|
+
if (!fs.existsSync(hooksDir)) {
|
|
78
|
+
fs.mkdirSync(hooksDir, { recursive: true });
|
|
79
|
+
}
|
|
80
|
+
// Create the hook script
|
|
81
|
+
const scriptName = isWin ? "perceptia-ground.ps1" : "perceptia-ground.sh";
|
|
82
|
+
const scriptPath = path.join(hooksDir, scriptName);
|
|
83
|
+
if (isWin) {
|
|
84
|
+
fs.writeFileSync(scriptPath, `$query = $env:CLAUDE_USER_PROMPT
|
|
85
|
+
if (-not $query) { exit 0 }
|
|
86
|
+
try {
|
|
87
|
+
$body = @{ query = $query } | ConvertTo-Json -Compress
|
|
88
|
+
$headers = @{ "Authorization" = "Bearer ${apiKey}"; "Content-Type" = "application/json"; "X-Fingerprint" = "hook-claude-${apiKey.slice(-8)}" }
|
|
89
|
+
$r = Invoke-RestMethod -Uri "https://api.perceptiamcp.com/v1/ground" -Method POST -Body $body -Headers $headers -ErrorAction Stop
|
|
90
|
+
if ($r) { Write-Output $r }
|
|
91
|
+
} catch { exit 0 }
|
|
92
|
+
`, "utf-8");
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
fs.writeFileSync(scriptPath, `#!/bin/bash
|
|
96
|
+
QUERY="$CLAUDE_USER_PROMPT"
|
|
97
|
+
[ -z "$QUERY" ] && exit 0
|
|
98
|
+
BODY=$(printf '{"query":"%s"}' "$QUERY")
|
|
99
|
+
RESULT=$(curl -s -f "https://api.perceptiamcp.com/v1/ground" \\
|
|
100
|
+
-H "Authorization: Bearer ${apiKey}" \\
|
|
101
|
+
-H "Content-Type: application/json" \\
|
|
102
|
+
-H "X-Fingerprint: hook-claude-${apiKey.slice(-8)}" \\
|
|
103
|
+
-d "$BODY" 2>/dev/null) || exit 0
|
|
104
|
+
[ -n "$RESULT" ] && echo "$RESULT"
|
|
105
|
+
`, "utf-8");
|
|
106
|
+
fs.chmodSync(scriptPath, 0o755);
|
|
107
|
+
}
|
|
108
|
+
// Add hook to settings.json
|
|
109
|
+
if (!config.hooks || typeof config.hooks !== "object") {
|
|
110
|
+
config.hooks = {};
|
|
111
|
+
}
|
|
112
|
+
const hooks = config.hooks;
|
|
113
|
+
const hookCommand = isWin
|
|
114
|
+
? `powershell -ExecutionPolicy Bypass -File "${scriptPath}"`
|
|
115
|
+
: scriptPath;
|
|
116
|
+
hooks.UserPromptSubmit = [
|
|
117
|
+
{
|
|
118
|
+
hooks: [
|
|
119
|
+
{
|
|
120
|
+
type: "command",
|
|
121
|
+
command: hookCommand,
|
|
122
|
+
timeout: 10,
|
|
123
|
+
shell: isWin ? "powershell" : "bash",
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
},
|
|
127
|
+
];
|
|
128
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
129
|
+
}
|
|
61
130
|
export async function runSetup(apiKey) {
|
|
62
131
|
if (!apiKey.startsWith("ck_live_")) {
|
|
63
132
|
console.error("Error: Invalid API key format. Keys start with ck_live_");
|
|
@@ -96,10 +165,14 @@ export async function runSetup(apiKey) {
|
|
|
96
165
|
for (const client of clients) {
|
|
97
166
|
writeConfig(client.configPath, apiKey);
|
|
98
167
|
console.log(` + ${client.name} — configured at ${client.configPath}`);
|
|
168
|
+
if (client.type === "claude-code") {
|
|
169
|
+
setupHook(client.configPath, apiKey);
|
|
170
|
+
console.log(` + ${client.name} — auto-grounding hook installed`);
|
|
171
|
+
}
|
|
99
172
|
}
|
|
100
173
|
console.log("");
|
|
101
174
|
console.log("Done! Restart your AI client to activate Perceptia grounding.");
|
|
102
175
|
console.log("");
|
|
103
|
-
console.log("
|
|
104
|
-
console.log("
|
|
176
|
+
console.log("Perceptia will automatically ground every prompt with relevant context.");
|
|
177
|
+
console.log("No action needed — just use your AI client as usual.");
|
|
105
178
|
}
|