@arkheia/mcp-server 0.1.4 → 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/README.md +177 -89
- 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 -56
- package/scripts/setup.js +35 -13
- package/bin/arkheia-mcp.js +0 -207
- package/python/mcp_server/__init__.py +0 -0
- package/python/requirements.txt +0 -4
package/package.json
CHANGED
|
@@ -1,56 +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
|
-
"cline",
|
|
38
|
-
"copilot"
|
|
39
|
-
],
|
|
40
|
-
"author": "Arkheia AI <support@arkheia.ai>",
|
|
41
|
-
"license": "MIT",
|
|
42
|
-
"homepage": "https://arkheia.ai/mcp",
|
|
43
|
-
"repository": {
|
|
44
|
-
"type": "git",
|
|
45
|
-
"url": "git+https://github.com/arkheiaai/arkheia-mcp.git"
|
|
46
|
-
},
|
|
47
|
-
"engines": {
|
|
48
|
-
"node": ">=18.0.0"
|
|
49
|
-
},
|
|
50
|
-
"files": [
|
|
51
|
-
"bin/",
|
|
52
|
-
"scripts/",
|
|
53
|
-
"python/",
|
|
54
|
-
"README.md"
|
|
55
|
-
]
|
|
56
|
-
}
|
|
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/scripts/setup.js
CHANGED
|
@@ -54,16 +54,27 @@ function saveConfig(apiKey) {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
function checkPython() {
|
|
57
|
-
|
|
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
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
}
|
package/bin/arkheia-mcp.js
DELETED
|
@@ -1,207 +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 ARKHEIA_HOME = path.join(
|
|
26
|
-
process.env.HOME || process.env.USERPROFILE || "/tmp",
|
|
27
|
-
".arkheia"
|
|
28
|
-
);
|
|
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
|
-
|
|
67
|
-
function findPython() {
|
|
68
|
-
const candidates = ["python3", "python"];
|
|
69
|
-
for (const cmd of candidates) {
|
|
70
|
-
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;
|
|
78
|
-
}
|
|
79
|
-
} catch {
|
|
80
|
-
// Try next candidate
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
return null;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function ensureVenv(python) {
|
|
87
|
-
const venvPython =
|
|
88
|
-
process.platform === "win32"
|
|
89
|
-
? path.join(VENV_DIR, "Scripts", "python.exe")
|
|
90
|
-
: path.join(VENV_DIR, "bin", "python");
|
|
91
|
-
|
|
92
|
-
if (!fs.existsSync(venvPython)) {
|
|
93
|
-
process.stderr.write("[arkheia] Creating virtual environment...\n");
|
|
94
|
-
execSync(`${python} -m venv "${VENV_DIR}"`, { stdio: "inherit" });
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return venvPython;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function installDeps(venvPython) {
|
|
101
|
-
const marker = path.join(VENV_DIR, ".arkheia-deps-installed");
|
|
102
|
-
if (fs.existsSync(marker)) {
|
|
103
|
-
return; // Already installed
|
|
104
|
-
}
|
|
105
|
-
|
|
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());
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function main() {
|
|
116
|
-
const python = findPython();
|
|
117
|
-
if (!python) {
|
|
118
|
-
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"
|
|
121
|
-
);
|
|
122
|
-
process.exit(1);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// ── Load config from ~/.arkheia/config.json ──────────────────
|
|
126
|
-
const configPath = path.join(
|
|
127
|
-
process.env.HOME || process.env.USERPROFILE || "/tmp",
|
|
128
|
-
".arkheia",
|
|
129
|
-
"config.json"
|
|
130
|
-
);
|
|
131
|
-
let arkheiaConfig = {};
|
|
132
|
-
try {
|
|
133
|
-
if (fs.existsSync(configPath)) {
|
|
134
|
-
arkheiaConfig = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
135
|
-
process.stderr.write(`[arkheia] Loaded config from ${configPath}\n`);
|
|
136
|
-
}
|
|
137
|
-
} catch (err) {
|
|
138
|
-
process.stderr.write(
|
|
139
|
-
`[arkheia] Warning: Could not read ${configPath}: ${err.message}\n`
|
|
140
|
-
);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Inject API key from config if not already in env
|
|
144
|
-
if (!process.env.ARKHEIA_API_KEY && arkheiaConfig.api_key) {
|
|
145
|
-
process.env.ARKHEIA_API_KEY = arkheiaConfig.api_key;
|
|
146
|
-
process.stderr.write("[arkheia] API key loaded from config.json\n");
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Inject hosted URL from config if not already in env
|
|
150
|
-
if (!process.env.ARKHEIA_HOSTED_URL && arkheiaConfig.proxy_url) {
|
|
151
|
-
process.env.ARKHEIA_HOSTED_URL = arkheiaConfig.proxy_url;
|
|
152
|
-
process.stderr.write(`[arkheia] Hosted URL: ${arkheiaConfig.proxy_url}\n`);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Check for API key
|
|
156
|
-
if (!process.env.ARKHEIA_API_KEY) {
|
|
157
|
-
process.stderr.write(
|
|
158
|
-
"[arkheia] Warning: ARKHEIA_API_KEY not set.\n" +
|
|
159
|
-
"Get a free API key at https://arkheia.ai/mcp\n" +
|
|
160
|
-
"Then set: export ARKHEIA_API_KEY=ak_live_...\n\n"
|
|
161
|
-
);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
let venvPython;
|
|
165
|
-
try {
|
|
166
|
-
venvPython = ensureVenv(python);
|
|
167
|
-
installDeps(venvPython);
|
|
168
|
-
} catch (err) {
|
|
169
|
-
process.stderr.write(
|
|
170
|
-
`[arkheia] Error setting up Python environment: ${err.message}\n`
|
|
171
|
-
);
|
|
172
|
-
process.exit(1);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Spawn the MCP server with stdio transport
|
|
176
|
-
const child = spawn(
|
|
177
|
-
venvPython,
|
|
178
|
-
["-m", "mcp_server.server"],
|
|
179
|
-
{
|
|
180
|
-
cwd: PYTHON_DIR,
|
|
181
|
-
stdio: ["pipe", "pipe", "inherit"], // stdin/stdout piped, stderr inherited
|
|
182
|
-
env: {
|
|
183
|
-
...process.env,
|
|
184
|
-
PYTHONPATH: PYTHON_DIR,
|
|
185
|
-
},
|
|
186
|
-
}
|
|
187
|
-
);
|
|
188
|
-
|
|
189
|
-
// Forward stdio for MCP protocol
|
|
190
|
-
process.stdin.pipe(child.stdin);
|
|
191
|
-
child.stdout.pipe(process.stdout);
|
|
192
|
-
|
|
193
|
-
child.on("error", (err) => {
|
|
194
|
-
process.stderr.write(`[arkheia] Failed to start MCP server: ${err.message}\n`);
|
|
195
|
-
process.exit(1);
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
child.on("exit", (code) => {
|
|
199
|
-
process.exit(code || 0);
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
// Forward signals
|
|
203
|
-
process.on("SIGINT", () => child.kill("SIGINT"));
|
|
204
|
-
process.on("SIGTERM", () => child.kill("SIGTERM"));
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
main();
|
|
File without changes
|
package/python/requirements.txt
DELETED