@arkheia/mcp-server 0.1.5 → 0.1.6
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/index.js +219 -0
- package/dist/memory.js +187 -0
- package/dist/providers.js +320 -0
- package/dist/proxy-client.js +219 -0
- package/dist/tool-registry.js +90 -0
- package/package.json +36 -57
- package/bin/arkheia-mcp.js +0 -240
- package/python/mcp_server/__init__.py +0 -0
- package/python/requirements.txt +0 -4
package/package.json
CHANGED
|
@@ -1,57 +1,36 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@arkheia/mcp-server",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"bin": {
|
|
7
|
-
"mcp-server": "
|
|
8
|
-
},
|
|
9
|
-
"scripts": {
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
"
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"windsurf",
|
|
38
|
-
"cline",
|
|
39
|
-
"copilot"
|
|
40
|
-
],
|
|
41
|
-
"author": "Arkheia AI <support@arkheia.ai>",
|
|
42
|
-
"license": "MIT",
|
|
43
|
-
"homepage": "https://arkheia.ai/mcp",
|
|
44
|
-
"repository": {
|
|
45
|
-
"type": "git",
|
|
46
|
-
"url": "git+https://github.com/arkheiaai/arkheia-mcp.git"
|
|
47
|
-
},
|
|
48
|
-
"engines": {
|
|
49
|
-
"node": ">=18.0.0"
|
|
50
|
-
},
|
|
51
|
-
"files": [
|
|
52
|
-
"bin/",
|
|
53
|
-
"scripts/",
|
|
54
|
-
"python/",
|
|
55
|
-
"README.md"
|
|
56
|
-
]
|
|
57
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@arkheia/mcp-server",
|
|
3
|
+
"version": "0.1.6",
|
|
4
|
+
"description": "Arkheia MCP Server — Fabrication detection for AI agents. Know when your AI is making things up.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"mcp-server": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"start": "node dist/index.js",
|
|
12
|
+
"prepublishOnly": "npm run build",
|
|
13
|
+
"postinstall": "node scripts/setup.js"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist/",
|
|
17
|
+
"scripts/",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"keywords": ["mcp", "ai", "fabrication", "detection", "hallucination", "governance"],
|
|
21
|
+
"author": "Arkheia AI <dmurfet@arkheia.ai>",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=18.0.0"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
28
|
+
"sql.js": "^1.11.0",
|
|
29
|
+
"zod": "^3.23.8"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/sql.js": "^1.4.9",
|
|
33
|
+
"@types/node": "^20.14.10",
|
|
34
|
+
"typescript": "^5.5.3"
|
|
35
|
+
}
|
|
36
|
+
}
|
package/bin/arkheia-mcp.js
DELETED
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Arkheia MCP Server — thin Node wrapper that spawns the Python MCP server.
|
|
4
|
-
*
|
|
5
|
-
* This wrapper exists so that MCP clients can install via:
|
|
6
|
-
* npx @arkheia/mcp-server
|
|
7
|
-
* npm install -g @arkheia/mcp-server
|
|
8
|
-
*
|
|
9
|
-
* It:
|
|
10
|
-
* 1. Locates a Python 3.10+ interpreter
|
|
11
|
-
* 2. Ensures mcp_server dependencies are installed (pip install)
|
|
12
|
-
* 3. Spawns `python -m mcp_server.server` with stdio transport
|
|
13
|
-
* 4. Forwards stdin/stdout/stderr (MCP uses stdio)
|
|
14
|
-
*
|
|
15
|
-
* Environment variables:
|
|
16
|
-
* ARKHEIA_API_KEY — API key for hosted detection (required)
|
|
17
|
-
* ARKHEIA_PROXY_URL — Local proxy URL (optional, for enterprise)
|
|
18
|
-
* ARKHEIA_HOSTED_URL — Hosted API URL (default: https://arkheia-proxy-production.up.railway.app)
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
const { spawn, execSync } = require("child_process");
|
|
22
|
-
const path = require("path");
|
|
23
|
-
const fs = require("fs");
|
|
24
|
-
|
|
25
|
-
const PYTHON_DIR = path.join(__dirname, "..", "python");
|
|
26
|
-
const REQUIREMENTS = path.join(PYTHON_DIR, "requirements.txt");
|
|
27
|
-
const VENV_DIR = path.join(
|
|
28
|
-
process.env.HOME || process.env.USERPROFILE || "/tmp",
|
|
29
|
-
".arkheia",
|
|
30
|
-
"venv"
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
function findPython() {
|
|
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"];
|
|
38
|
-
for (const cmd of candidates) {
|
|
39
|
-
try {
|
|
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
|
-
}
|
|
54
|
-
}
|
|
55
|
-
} catch {
|
|
56
|
-
// Try next candidate
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return null;
|
|
60
|
-
}
|
|
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
|
-
|
|
74
|
-
function ensureVenv(python) {
|
|
75
|
-
const venvPython =
|
|
76
|
-
process.platform === "win32"
|
|
77
|
-
? path.join(VENV_DIR, "Scripts", "python.exe")
|
|
78
|
-
: path.join(VENV_DIR, "bin", "python");
|
|
79
|
-
|
|
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
|
-
}
|
|
85
|
-
process.stderr.write("[arkheia] Creating virtual environment...\n");
|
|
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);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return venvPython;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function installDeps(venvPython) {
|
|
96
|
-
const marker = path.join(VENV_DIR, ".arkheia-deps-installed");
|
|
97
|
-
if (fs.existsSync(marker)) {
|
|
98
|
-
return; // Already installed
|
|
99
|
-
}
|
|
100
|
-
|
|
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
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
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
|
-
|
|
141
|
-
const python = findPython();
|
|
142
|
-
if (!python) {
|
|
143
|
-
process.stderr.write(
|
|
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"
|
|
153
|
-
);
|
|
154
|
-
process.exit(1);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// ── Load config from ~/.arkheia/config.json ──────────────────
|
|
158
|
-
const configPath = path.join(
|
|
159
|
-
process.env.HOME || process.env.USERPROFILE || "/tmp",
|
|
160
|
-
".arkheia",
|
|
161
|
-
"config.json"
|
|
162
|
-
);
|
|
163
|
-
let arkheiaConfig = {};
|
|
164
|
-
try {
|
|
165
|
-
if (fs.existsSync(configPath)) {
|
|
166
|
-
arkheiaConfig = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
167
|
-
process.stderr.write(`[arkheia] Loaded config from ${configPath}\n`);
|
|
168
|
-
}
|
|
169
|
-
} catch (err) {
|
|
170
|
-
process.stderr.write(
|
|
171
|
-
`[arkheia] Warning: Could not read ${configPath}: ${err.message}\n`
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Inject API key from config if not already in env
|
|
176
|
-
if (!process.env.ARKHEIA_API_KEY && arkheiaConfig.api_key) {
|
|
177
|
-
process.env.ARKHEIA_API_KEY = arkheiaConfig.api_key;
|
|
178
|
-
process.stderr.write("[arkheia] API key loaded from config.json\n");
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// Inject hosted URL from config if not already in env
|
|
182
|
-
if (!process.env.ARKHEIA_HOSTED_URL && arkheiaConfig.proxy_url) {
|
|
183
|
-
process.env.ARKHEIA_HOSTED_URL = arkheiaConfig.proxy_url;
|
|
184
|
-
process.stderr.write(`[arkheia] Hosted URL: ${arkheiaConfig.proxy_url}\n`);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Check for API key
|
|
188
|
-
if (!process.env.ARKHEIA_API_KEY) {
|
|
189
|
-
process.stderr.write(
|
|
190
|
-
"[arkheia] Warning: ARKHEIA_API_KEY not set.\n" +
|
|
191
|
-
"Get a free API key at https://arkheia.ai/mcp\n" +
|
|
192
|
-
"Then set: export ARKHEIA_API_KEY=ak_live_...\n\n"
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
let venvPython;
|
|
197
|
-
try {
|
|
198
|
-
venvPython = ensureVenv(python);
|
|
199
|
-
installDeps(venvPython);
|
|
200
|
-
} catch (err) {
|
|
201
|
-
process.stderr.write(
|
|
202
|
-
`[arkheia] Error setting up Python environment: ${err.message}\n`
|
|
203
|
-
);
|
|
204
|
-
process.exit(1);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// Spawn the MCP server with stdio transport
|
|
208
|
-
const serverDir = PYTHON_DIR;
|
|
209
|
-
const child = spawn(
|
|
210
|
-
venvPython,
|
|
211
|
-
["-m", "mcp_server.server"],
|
|
212
|
-
{
|
|
213
|
-
cwd: serverDir,
|
|
214
|
-
stdio: ["pipe", "pipe", "inherit"], // stdin/stdout piped, stderr inherited
|
|
215
|
-
env: {
|
|
216
|
-
...process.env,
|
|
217
|
-
PYTHONPATH: serverDir,
|
|
218
|
-
},
|
|
219
|
-
}
|
|
220
|
-
);
|
|
221
|
-
|
|
222
|
-
// Forward stdio for MCP protocol
|
|
223
|
-
process.stdin.pipe(child.stdin);
|
|
224
|
-
child.stdout.pipe(process.stdout);
|
|
225
|
-
|
|
226
|
-
child.on("error", (err) => {
|
|
227
|
-
process.stderr.write(`[arkheia] Failed to start MCP server: ${err.message}\n`);
|
|
228
|
-
process.exit(1);
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
child.on("exit", (code) => {
|
|
232
|
-
process.exit(code || 0);
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
// Forward signals
|
|
236
|
-
process.on("SIGINT", () => child.kill("SIGINT"));
|
|
237
|
-
process.on("SIGTERM", () => child.kill("SIGTERM"));
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
main();
|
|
File without changes
|
package/python/requirements.txt
DELETED