@arkheia/mcp-server 0.1.3 → 0.1.5

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 CHANGED
@@ -1,89 +1,177 @@
1
- # Arkheia MCP Server — Fabrication Detection for AI Agents
2
-
3
- Know when your AI is making things up.
4
-
5
- Arkheia screens model responses for fabrication using behavioural fingerprinting. Works with Claude, GPT, Gemini, Grok, Llama, Mistral, and 30+ other models. One tool call. Real-time risk scoring.
6
-
7
- Free tier: 1,500 detections/month. No credit card.
8
-
9
- ## Quick Start
10
-
11
- ```bash
12
- npx @arkheia/mcp-server
13
- ```
14
-
15
- Get a free API key:
16
-
17
- ```bash
18
- curl -X POST https://arkheia-proxy-production.up.railway.app/v1/provision \
19
- -H "Content-Type: application/json" \
20
- -d '{"email": "you@example.com"}'
21
- ```
22
-
23
- Add to your agent config (Claude Code, Claude Desktop, Cursor, or any MCP-compatible tool):
24
-
25
- ```json
26
- {
27
- "mcpServers": {
28
- "arkheia": {
29
- "command": "python",
30
- "args": ["-m", "mcp_server.server"],
31
- "cwd": "~/.arkheia/mcp",
32
- "env": {
33
- "PYTHONPATH": "~/.arkheia/mcp",
34
- "ARKHEIA_API_KEY": "ak_live_your_key_here"
35
- }
36
- }
37
- }
38
- }
39
- ```
40
-
41
- Restart your agent. Then ask it:
42
-
43
- > "Use arkheia_verify to check this response: The Kafka 4.1 ConsumerLease API introduces a lease-based partition ownership model."
44
-
45
- It should flag this as **HIGH** risk — because the Kafka 4.1 ConsumerLease API doesn't exist.
46
-
47
- ## What You Get
48
-
49
- | Tool | Description |
50
- |------|-------------|
51
- | `arkheia_verify` | Score any model response for fabrication risk (LOW/MEDIUM/HIGH) |
52
- | `arkheia_audit_log` | Review your detection history |
53
- | `run_grok` | Call Grok + screen for fabrication |
54
- | `run_gemini` | Call Gemini + screen for fabrication |
55
- | `run_ollama` | Call local Ollama model + screen |
56
- | `run_together` | Call Together AI (Kimi, DeepSeek) + screen |
57
-
58
- ## 35+ Model Profiles
59
-
60
- GPT-4o, GPT-5.4, Claude Opus/Sonnet/Haiku, Gemini 2.5/3.0, Grok 4, Llama, Mixtral, CodeLlama, Falcon, Phi4, Kimi K2.5, and more. If your model isn't listed, [let us know](mailto:dmurfet@arkheia.ai).
61
-
62
- ## Pricing
63
-
64
- | Plan | Price | Detections |
65
- |------|-------|------------|
66
- | Free | $0 | 1,500/month |
67
- | Single Contributor | $99/month | Unlimited |
68
- | Professional | $499/month | Unlimited |
69
- | Team | $1,999/month | Unlimited |
70
-
71
- ## Full Documentation
72
-
73
- See the [GitHub repo](https://github.com/arkheiaai/arkheia-mcp) for:
74
- - Complete setup guide for all agents
75
- - CLAUDE.md template for automatic detection across projects
76
- - Multi-agent quorum pattern
77
- - Test prompts and examples
78
-
79
- ## Feedback
80
-
81
- - **GitHub Issues:** https://github.com/arkheiaai/arkheia-mcp/issues
82
- - **Email:** dmurfet@arkheia.ai
83
-
84
- Every message is read by the founder.
85
-
86
- ## Links
87
-
88
- - Website: https://arkheia.ai
89
- - GitHub: https://github.com/arkheiaai/arkheia-mcp
1
+ # Arkheia MCP Server — Fabrication Detection for AI Agents
2
+
3
+ Know when your AI is making things up.
4
+
5
+ Arkheia screens model responses for fabrication using behavioural fingerprinting. Works with Claude, GPT, Gemini, Grok, Llama, Mistral, and 30+ other models. One tool call. Real-time risk scoring.
6
+
7
+ Free tier: 1,500 detections/month. No credit card.
8
+
9
+ ## Prerequisites
10
+
11
+ ```
12
+ Requires:
13
+ - Node 18+
14
+ - Python 3.10–3.13 with working pyexpat
15
+
16
+ macOS note: Homebrew's current `brew install python` installs 3.14,
17
+ which has a broken pyexpat link. Use `brew install python@3.12` until
18
+ Homebrew ships a fix. Verify with:
19
+ python3.12 -c "import pyexpat, ensurepip"
20
+ ```
21
+
22
+ ## Install
23
+
24
+ ```bash
25
+ npm install -g @arkheia/mcp-server
26
+ ```
27
+
28
+ Get a free API key at [arkheia.ai/mcp/account](https://arkheia.ai/mcp/account), or via the CLI:
29
+
30
+ ```bash
31
+ curl -X POST https://arkheia-proxy-production.up.railway.app/v1/provision \
32
+ -H "Content-Type: application/json" \
33
+ -d '{"email": "you@example.com"}'
34
+ ```
35
+
36
+ Set your key:
37
+
38
+ ```bash
39
+ export ARKHEIA_API_KEY="ak_live_..."
40
+ ```
41
+
42
+ ## Register with your CLI
43
+
44
+ Each AI CLI has a slightly different `mcp add` command. Use the one that matches your tool. All assume you've installed globally with `npm install -g`.
45
+
46
+ ### Claude Code
47
+
48
+ ```bash
49
+ claude mcp add arkheia -s user \
50
+ -e ARKHEIA_API_KEY="$ARKHEIA_API_KEY" \
51
+ -- mcp-server
52
+ ```
53
+
54
+ Config lands in: `~/.claude.json` under `mcpServers.arkheia`
55
+
56
+ ### Codex
57
+
58
+ ```bash
59
+ codex mcp add arkheia \
60
+ --env ARKHEIA_API_KEY="$ARKHEIA_API_KEY" \
61
+ -- mcp-server
62
+ ```
63
+
64
+ Config lands in: `~/.codex/config.toml` under `[mcp_servers.arkheia.env]`
65
+
66
+ Note: `codex login --api-key` is deprecated. Use `printenv OPENAI_API_KEY | codex login --with-api-key` instead.
67
+
68
+ ### Gemini
69
+
70
+ ```bash
71
+ gemini mcp add -s user \
72
+ -e ARKHEIA_API_KEY="$ARKHEIA_API_KEY" \
73
+ arkheia mcp-server
74
+ ```
75
+
76
+ Config lands in: `~/.gemini/settings.json` under `mcpServers.arkheia`
77
+
78
+ **Gotcha:** `gemini mcp list` only shows project-scope servers. If you registered with `-s user`, verify by reading `~/.gemini/settings.json` directly.
79
+
80
+ **Gotcha:** Don't use `npx -y @arkheia/mcp-server` with Gemini — the `-y` flag gets eaten by Gemini's yargs parser as `--yolo`. Use the globally-installed `mcp-server` binary directly.
81
+
82
+ ### Grok
83
+
84
+ ```bash
85
+ grok mcp add arkheia \
86
+ -t stdio \
87
+ -c mcp-server \
88
+ -e ARKHEIA_API_KEY="$ARKHEIA_API_KEY"
89
+ ```
90
+
91
+ Config lands in: `~/.grok/settings.json` under `mcpServers.arkheia` (note: env is nested under `transport`, unlike other CLIs)
92
+
93
+ ## Verify it works
94
+
95
+ ```bash
96
+ # Claude Code — live connection test
97
+ claude mcp list
98
+
99
+ # Codex — shows 'enabled' (not a live check)
100
+ codex mcp list
101
+
102
+ # Grok — best: spawns the server and lists all 9 tools
103
+ grok mcp test arkheia
104
+
105
+ # Gemini — no built-in test; start a session and try the tool
106
+ ```
107
+
108
+ **Important:** MCP registrations are not hot-reloaded. Restart your CLI session after running `mcp add`.
109
+
110
+ ## What You Get
111
+
112
+ | Tool | Description |
113
+ |------|-------------|
114
+ | `arkheia_verify` | Score any model response for fabrication risk (LOW/MEDIUM/HIGH) |
115
+ | `arkheia_audit_log` | Review your detection history |
116
+ | `run_grok` | Call Grok + screen for fabrication |
117
+ | `run_gemini` | Call Gemini + screen for fabrication |
118
+ | `run_ollama` | Call local Ollama model + screen |
119
+ | `run_together` | Call Together AI (Kimi, DeepSeek) + screen |
120
+ | `memory_store` | Persistent knowledge graph — upsert entity |
121
+ | `memory_retrieve` | Knowledge graph lookup |
122
+ | `memory_relate` | Create relationship between entities |
123
+
124
+ ## 35+ Model Profiles
125
+
126
+ GPT-4o, GPT-5.4, Claude Opus/Sonnet/Haiku, Gemini 2.5/3.0, Grok 4, Llama, Mixtral, CodeLlama, Falcon, Phi4, Kimi K2.5, and more. If your model isn't listed, [let us know](mailto:dmurfet@arkheia.ai).
127
+
128
+ ## Pricing
129
+
130
+ | Plan | Price | Detections |
131
+ |------|-------|------------|
132
+ | Free | $0 | 1,500/month |
133
+ | Single Contributor | $99/month | Unlimited |
134
+ | Professional | $499/month | Unlimited |
135
+ | Team | $1,999/month | Unlimited |
136
+
137
+ Manage your account at [arkheia.ai/mcp/account](https://arkheia.ai/mcp/account).
138
+
139
+ ## Where API keys are stored
140
+
141
+ | CLI | Config file | Key location |
142
+ |-----|-------------|-------------|
143
+ | Claude Code | `~/.claude.json` | `mcpServers.arkheia.env.ARKHEIA_API_KEY` |
144
+ | Codex | `~/.codex/config.toml` | `[mcp_servers.arkheia.env]` section |
145
+ | Gemini | `~/.gemini/settings.json` | `mcpServers.arkheia.env.ARKHEIA_API_KEY` |
146
+ | Grok | `~/.grok/settings.json` | `mcpServers.arkheia.transport.env.ARKHEIA_API_KEY` |
147
+
148
+ ## Troubleshooting
149
+
150
+ **"Python 3.10+ is required but not found"** — Install Python 3.12: `brew install python@3.12` (macOS) or download from [python.org](https://python.org).
151
+
152
+ **"No module named pip"** — Your Python installation has broken pip (common with Python 3.14 on macOS). Delete `~/.arkheia/venv` and switch to Python 3.12: `brew install python@3.12`.
153
+
154
+ **Server registered but tools not showing** — Restart your CLI session. MCP registrations are not hot-reloaded.
155
+
156
+ **API key rejected** — Check for trailing whitespace or `\r` characters. If your env file was created on Windows, run `dos2unix` on it. The server will warn about this on startup.
157
+
158
+ ## Full Documentation
159
+
160
+ See the [GitHub repo](https://github.com/arkheiaai/arkheia-mcp) for:
161
+ - Complete setup guide for all agents
162
+ - CLAUDE.md template for automatic detection across projects
163
+ - Multi-agent quorum pattern
164
+ - Test prompts and examples
165
+
166
+ ## Feedback
167
+
168
+ - **GitHub Issues:** https://github.com/arkheiaai/arkheia-mcp/issues
169
+ - **Email:** dmurfet@arkheia.ai
170
+
171
+ Every message is read by the founder.
172
+
173
+ ## Links
174
+
175
+ - Website: https://arkheia.ai
176
+ - MCP Account: https://arkheia.ai/mcp/account
177
+ - GitHub: https://github.com/arkheiaai/arkheia-mcp
@@ -22,59 +22,35 @@ const { spawn, execSync } = require("child_process");
22
22
  const path = require("path");
23
23
  const fs = require("fs");
24
24
 
25
- const ARKHEIA_HOME = path.join(
25
+ const PYTHON_DIR = path.join(__dirname, "..", "python");
26
+ const REQUIREMENTS = path.join(PYTHON_DIR, "requirements.txt");
27
+ const VENV_DIR = path.join(
26
28
  process.env.HOME || process.env.USERPROFILE || "/tmp",
27
- ".arkheia"
29
+ ".arkheia",
30
+ "venv"
28
31
  );
29
- const REPO_DIR = path.join(ARKHEIA_HOME, "mcp");
30
- const BUNDLED_PYTHON_DIR = path.join(__dirname, "..", "python");
31
- const VENV_DIR = path.join(ARKHEIA_HOME, "venv");
32
-
33
- // Determine the real Python source: cloned repo > bundled package
34
- function getServerDir() {
35
- // If repo already cloned, use it
36
- if (fs.existsSync(path.join(REPO_DIR, "mcp_server", "server.py"))) {
37
- return REPO_DIR;
38
- }
39
- // If bundled package has the server code, use it
40
- if (fs.existsSync(path.join(BUNDLED_PYTHON_DIR, "mcp_server", "server.py"))) {
41
- return BUNDLED_PYTHON_DIR;
42
- }
43
- // Neither exists — clone the repo
44
- process.stderr.write("[arkheia] Server code not found. Cloning from GitHub...\n");
45
- try {
46
- if (!fs.existsSync(ARKHEIA_HOME)) fs.mkdirSync(ARKHEIA_HOME, { recursive: true });
47
- execSync(`git clone --depth 1 https://github.com/arkheiaai/arkheia-mcp.git "${REPO_DIR}"`, {
48
- stdio: "inherit",
49
- timeout: 60000,
50
- });
51
- process.stderr.write("[arkheia] Repository cloned successfully.\n");
52
- return REPO_DIR;
53
- } catch (err) {
54
- process.stderr.write(
55
- `[arkheia] Error: Could not clone repository: ${err.message}\n` +
56
- "Manual install: git clone https://github.com/arkheiaai/arkheia-mcp.git ~/.arkheia/mcp\n"
57
- );
58
- process.exit(1);
59
- }
60
- }
61
-
62
- const PYTHON_DIR = getServerDir();
63
- const REQUIREMENTS = fs.existsSync(path.join(PYTHON_DIR, "mcp_server", "requirements.txt"))
64
- ? path.join(PYTHON_DIR, "mcp_server", "requirements.txt")
65
- : path.join(PYTHON_DIR, "requirements.txt");
66
32
 
67
33
  function findPython() {
68
- const candidates = ["python3", "python"];
34
+ // Try versioned interpreters first — on Homebrew, keg-only formulae like
35
+ // python@3.12 only expose the versioned binary (python3.12), not python3.
36
+ // Exclude 3.14: Homebrew's build has broken pyexpat on macOS as of Apr 2026.
37
+ const candidates = ["python3.13", "python3.12", "python3.11", "python3", "python"];
69
38
  for (const cmd of candidates) {
70
39
  try {
71
- const version = execSync(`${cmd} --version 2>&1`, {
72
- encoding: "utf-8",
73
- timeout: 5000,
74
- }).trim();
75
- const match = version.match(/Python (\d+)\.(\d+)/);
76
- if (match && parseInt(match[1]) >= 3 && parseInt(match[2]) >= 10) {
77
- return cmd;
40
+ // Check version AND that pyexpat + ensurepip actually work.
41
+ // Python 3.14 on macOS crashes on `import pyexpat` due to a missing
42
+ // libexpat symbol — this import check catches it at discovery time.
43
+ const output = execSync(
44
+ `${cmd} -c "import sys,pyexpat,ensurepip; print(f'{sys.version_info.major}.{sys.version_info.minor}')"`,
45
+ { encoding: "utf-8", timeout: 10000, stdio: ["pipe", "pipe", "pipe"] }
46
+ ).trim();
47
+ const match = output.match(/^(\d+)\.(\d+)$/);
48
+ if (match) {
49
+ const major = parseInt(match[1]);
50
+ const minor = parseInt(match[2]);
51
+ if (major === 3 && minor >= 10 && minor <= 13) {
52
+ return cmd;
53
+ }
78
54
  }
79
55
  } catch {
80
56
  // Try next candidate
@@ -83,15 +59,34 @@ function findPython() {
83
59
  return null;
84
60
  }
85
61
 
62
+ function venvIsHealthy(venvPython) {
63
+ if (!fs.existsSync(venvPython)) return false;
64
+ try {
65
+ execSync(`"${venvPython}" -m pip --version`, {
66
+ encoding: "utf-8", timeout: 10000, stdio: ["pipe", "pipe", "pipe"],
67
+ });
68
+ return true;
69
+ } catch {
70
+ return false;
71
+ }
72
+ }
73
+
86
74
  function ensureVenv(python) {
87
75
  const venvPython =
88
76
  process.platform === "win32"
89
77
  ? path.join(VENV_DIR, "Scripts", "python.exe")
90
78
  : path.join(VENV_DIR, "bin", "python");
91
79
 
92
- if (!fs.existsSync(venvPython)) {
80
+ if (!venvIsHealthy(venvPython)) {
81
+ if (fs.existsSync(VENV_DIR)) {
82
+ process.stderr.write("[arkheia] Existing venv is unhealthy (pip broken or missing). Recreating...\n");
83
+ fs.rmSync(VENV_DIR, { recursive: true, force: true });
84
+ }
93
85
  process.stderr.write("[arkheia] Creating virtual environment...\n");
94
86
  execSync(`${python} -m venv "${VENV_DIR}"`, { stdio: "inherit" });
87
+ // Force-reinstall deps after venv recreation
88
+ const marker = path.join(VENV_DIR, ".arkheia-deps-installed");
89
+ if (fs.existsSync(marker)) fs.unlinkSync(marker);
95
90
  }
96
91
 
97
92
  return venvPython;
@@ -103,21 +98,58 @@ function installDeps(venvPython) {
103
98
  return; // Already installed
104
99
  }
105
100
 
106
- process.stderr.write("[arkheia] Installing dependencies...\n");
107
- execSync(`"${venvPython}" -m pip install --quiet -r "${REQUIREMENTS}"`, {
108
- stdio: "inherit",
109
- timeout: 120000,
110
- });
111
-
112
- fs.writeFileSync(marker, new Date().toISOString());
101
+ const logFile = path.join(ARKHEIA_HOME, "install.log");
102
+ process.stderr.write("[arkheia] Installing Python dependencies (first run)...\n");
103
+ const start = Date.now();
104
+ try {
105
+ const output = execSync(`"${venvPython}" -m pip install -r "${REQUIREMENTS}" 2>&1`, {
106
+ encoding: "utf-8",
107
+ timeout: 300000, // 5 min — slow networks exist
108
+ });
109
+ const elapsed = ((Date.now() - start) / 1000).toFixed(1);
110
+ // Count installed packages from pip output
111
+ const installed = (output.match(/Successfully installed/g) || []).length;
112
+ process.stderr.write(`[arkheia] Dependencies installed in ${elapsed}s\n`);
113
+ fs.writeFileSync(marker, new Date().toISOString());
114
+ } catch (err) {
115
+ const elapsed = ((Date.now() - start) / 1000).toFixed(1);
116
+ // Save full pip output for debugging
117
+ const pipOutput = err.stdout || err.stderr || err.message || "unknown error";
118
+ fs.writeFileSync(logFile, pipOutput);
119
+ process.stderr.write(
120
+ `[arkheia] Dependency install failed after ${elapsed}s.\n` +
121
+ `[arkheia] Full output saved to: ${logFile}\n` +
122
+ `[arkheia] Try: "${venvPython}" -m pip install -r "${REQUIREMENTS}"\n`
123
+ );
124
+ throw err;
125
+ }
113
126
  }
114
127
 
115
128
  function main() {
129
+ // ── CRLF warning — env files with Windows line endings silently break API keys
130
+ for (const k of ["ARKHEIA_API_KEY", "ARKHEIA_PROXY_URL", "ARKHEIA_HOSTED_URL"]) {
131
+ const v = process.env[k];
132
+ if (v && /[\r\n]/.test(v)) {
133
+ process.stderr.write(
134
+ `[arkheia] WARNING: ${k} contains whitespace/newline characters.\n` +
135
+ `[arkheia] Your env file may have Windows (CRLF) line endings. Run 'dos2unix' on it.\n`
136
+ );
137
+ process.env[k] = v.trim(); // auto-fix for this run
138
+ }
139
+ }
140
+
116
141
  const python = findPython();
117
142
  if (!python) {
118
143
  process.stderr.write(
119
- "[arkheia] Error: Python 3.10+ is required but not found.\n" +
120
- "Install Python from https://python.org and try again.\n"
144
+ "[arkheia] Error: Python 3.10–3.13 is required but not found.\n\n" +
145
+ " macOS (Homebrew):\n" +
146
+ " brew install python@3.12\n\n" +
147
+ " NOTE: Homebrew's current default 'brew install python' installs 3.14,\n" +
148
+ " which has a broken pyexpat link on macOS as of April 2026.\n" +
149
+ " Use python@3.12 until Homebrew ships a fix.\n\n" +
150
+ " After installing, verify with:\n" +
151
+ " python3.12 -c \"import pyexpat, ensurepip\"\n\n" +
152
+ " Other platforms: https://python.org\n"
121
153
  );
122
154
  process.exit(1);
123
155
  }
@@ -173,15 +205,16 @@ function main() {
173
205
  }
174
206
 
175
207
  // Spawn the MCP server with stdio transport
208
+ const serverDir = PYTHON_DIR;
176
209
  const child = spawn(
177
210
  venvPython,
178
211
  ["-m", "mcp_server.server"],
179
212
  {
180
- cwd: PYTHON_DIR,
213
+ cwd: serverDir,
181
214
  stdio: ["pipe", "pipe", "inherit"], // stdin/stdout piped, stderr inherited
182
215
  env: {
183
216
  ...process.env,
184
- PYTHONPATH: PYTHON_DIR,
217
+ PYTHONPATH: serverDir,
185
218
  },
186
219
  }
187
220
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkheia/mcp-server",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "mcpName": "io.github.arkheiaai/mcp-server",
5
5
  "description": "Arkheia MCP Server — Fabrication detection for LLM outputs. Detect hallucination in any model's output with a single tool call.",
6
6
  "bin": {
@@ -8,22 +8,35 @@
8
8
  },
9
9
  "scripts": {
10
10
  "start": "node bin/arkheia-mcp.js",
11
- "postinstall": "node scripts/setup.js"
11
+ "postinstall": "node scripts/setup.js",
12
+ "release": "npm version patch --no-git-tag-version && npm publish --access public && node -e \"const{execSync}=require('child_process');const p=require('./package.json');const s=JSON.parse(require('fs').readFileSync('server.json','utf8'));s.version=p.version;s.packages[0].version=p.version;require('fs').writeFileSync('server.json',JSON.stringify(s,null,2));execSync('mcp-publisher publish',{stdio:'inherit'})\" && echo 'Published to npm + MCP registry'"
12
13
  },
13
14
  "keywords": [
14
15
  "mcp",
15
- "ai",
16
- "fabrication",
17
- "hallucination",
18
- "detection",
19
- "llm",
16
+ "mcp-server",
17
+ "model-context-protocol",
18
+ "ai-safety",
19
+ "ai-governance",
20
+ "fabrication-detection",
21
+ "hallucination-detection",
22
+ "llm-verification",
23
+ "llm-grounding",
24
+ "ai-agent",
25
+ "agent-governance",
26
+ "ai-trust",
27
+ "ai-audit",
28
+ "ai-compliance",
29
+ "fact-checking",
20
30
  "claude",
21
31
  "gpt",
22
32
  "gemini",
23
- "governance",
24
- "audit",
25
- "grounding",
26
- "verification"
33
+ "llama",
34
+ "anthropic",
35
+ "openai",
36
+ "cursor",
37
+ "windsurf",
38
+ "cline",
39
+ "copilot"
27
40
  ],
28
41
  "author": "Arkheia AI <support@arkheia.ai>",
29
42
  "license": "MIT",
package/scripts/setup.js CHANGED
@@ -54,16 +54,27 @@ function saveConfig(apiKey) {
54
54
  }
55
55
 
56
56
  function checkPython() {
57
- const candidates = ["python3", "python"];
57
+ // Try versioned interpreters first — on Homebrew, keg-only formulae like
58
+ // python@3.12 only expose python3.12, not python3.
59
+ const candidates = ["python3.13", "python3.12", "python3.11", "python3", "python"];
58
60
  for (const cmd of candidates) {
59
61
  try {
60
- const version = execSync(`${cmd} --version 2>&1`, {
61
- encoding: "utf-8",
62
- timeout: 5000,
63
- }).trim();
64
- const match = version.match(/Python (\d+)\.(\d+)/);
65
- if (match && parseInt(match[1]) >= 3 && parseInt(match[2]) >= 10) {
66
- return { cmd, version };
62
+ // Verify version AND that pyexpat + ensurepip work.
63
+ // Python 3.14 on macOS has broken pyexpat (missing libexpat symbol).
64
+ const output = execSync(
65
+ `${cmd} -c "import sys,pyexpat,ensurepip; print(f'{sys.version_info.major}.{sys.version_info.minor}')"`,
66
+ { encoding: "utf-8", timeout: 10000, stdio: ["pipe", "pipe", "pipe"] }
67
+ ).trim();
68
+ const match = output.match(/^(\d+)\.(\d+)$/);
69
+ if (match) {
70
+ const major = parseInt(match[1]);
71
+ const minor = parseInt(match[2]);
72
+ if (major === 3 && minor >= 10 && minor <= 13) {
73
+ const version = execSync(`${cmd} --version 2>&1`, {
74
+ encoding: "utf-8", timeout: 5000,
75
+ }).trim();
76
+ return { cmd, version };
77
+ }
67
78
  }
68
79
  } catch {
69
80
  // Try next
@@ -75,19 +86,30 @@ function checkPython() {
75
86
  const python = checkPython();
76
87
 
77
88
  if (!python) {
78
- console.log(`
89
+ console.error(`
79
90
  ============================================================
80
- Arkheia MCP Server requires Python 3.10+
91
+ ERROR: Arkheia MCP Server requires Python 3.10–3.13
92
+ with working pyexpat and ensurepip.
93
+
94
+ macOS (Homebrew):
95
+ brew install python@3.12
96
+
97
+ NOTE: Homebrew's current default 'brew install python'
98
+ installs 3.14, which has a broken pyexpat link on macOS
99
+ as of April 2026. Use python@3.12 until Homebrew ships a fix.
100
+
101
+ After installing, verify with:
102
+ python3.12 -c "import pyexpat, ensurepip"
81
103
 
82
- Install Python from: https://python.org
83
- Then run: npx @arkheia/mcp-server
104
+ Other platforms: https://python.org
84
105
  ============================================================
85
106
  `);
107
+ process.exit(1);
86
108
  } else {
87
109
  console.log(`
88
110
  ============================================================
89
111
  Arkheia MCP Server installed successfully.
90
- Python: ${python.version}
112
+ Python: ${python.version} (${python.cmd})
91
113
  ============================================================
92
114
  `);
93
115
  }