@vespermcp/mcp-server 1.2.21 ā 1.2.22
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 +49 -0
- package/build/cloud/adapters/supabase.js +49 -0
- package/build/cloud/storage-manager.js +6 -0
- package/build/export/exporter.js +22 -9
- package/build/gateway/unified-dataset-gateway.js +410 -0
- package/build/index.js +1587 -845
- package/build/ingestion/ingestor.js +7 -4
- package/build/install/install-service.js +11 -6
- package/build/lib/supabase.js +3 -0
- package/build/metadata/scraper.js +85 -14
- package/build/python/asset_downloader_engine.py +2 -0
- package/build/python/convert_engine.py +92 -0
- package/build/python/export_engine.py +45 -0
- package/build/python/kaggle_engine.py +77 -5
- package/build/python/normalize_engine.py +83 -0
- package/build/python/vesper/core/asset_downloader.py +5 -1
- package/build/search/engine.js +43 -5
- package/build/search/jit-orchestrator.js +18 -14
- package/build/search/query-intent.js +509 -0
- package/build/tools/formatter.js +6 -3
- package/build/utils/python-runtime.js +130 -0
- package/package.json +7 -5
- package/scripts/postinstall.cjs +87 -31
- package/scripts/wizard.cjs +601 -0
- package/scripts/wizard.js +306 -12
- package/src/python/__pycache__/config.cpython-312.pyc +0 -0
- package/src/python/__pycache__/kaggle_engine.cpython-312.pyc +0 -0
- package/src/python/asset_downloader_engine.py +2 -0
- package/src/python/convert_engine.py +92 -0
- package/src/python/export_engine.py +45 -0
- package/src/python/kaggle_engine.py +77 -5
- package/src/python/normalize_engine.py +83 -0
- package/src/python/requirements.txt +12 -0
- package/src/python/vesper/core/asset_downloader.py +5 -1
- package/wizard.cjs +3 -0
package/build/tools/formatter.js
CHANGED
|
@@ -54,7 +54,7 @@ export function formatSearchResults(results) {
|
|
|
54
54
|
results.forEach((ds, index) => {
|
|
55
55
|
const relevanceScore = ds.relevance_score || 0;
|
|
56
56
|
// Source badge and access level
|
|
57
|
-
const openSources = ["huggingface", "uci", "github", "worldbank", "nasa"];
|
|
57
|
+
const openSources = ["huggingface", "openml", "s3", "uci", "github", "worldbank", "nasa"];
|
|
58
58
|
const isOpen = openSources.includes(ds.source);
|
|
59
59
|
const sourceLabel = ds.source.charAt(0).toUpperCase() + ds.source.slice(1);
|
|
60
60
|
const accessBadge = isOpen ? "Open Access" : "Requires API Key";
|
|
@@ -131,7 +131,7 @@ export function formatDatasetInfo(ds) {
|
|
|
131
131
|
output += `${ds.name}\n`;
|
|
132
132
|
output += "ā".repeat(80) + "\n\n";
|
|
133
133
|
// Source and safety
|
|
134
|
-
const openSources = ["huggingface", "uci", "github", "worldbank", "nasa"];
|
|
134
|
+
const openSources = ["huggingface", "openml", "s3", "uci", "github", "worldbank", "nasa"];
|
|
135
135
|
const isOpen = openSources.includes(ds.source);
|
|
136
136
|
const sourceLabel = ds.source.charAt(0).toUpperCase() + ds.source.slice(1);
|
|
137
137
|
const accessBadge = isOpen ? "Open Access" : "Requires API Key";
|
|
@@ -149,7 +149,10 @@ export function formatDatasetInfo(ds) {
|
|
|
149
149
|
output += `Safety: ${safetyIndicator}\n`;
|
|
150
150
|
output += `ID: ${ds.id}\n\n`;
|
|
151
151
|
if (!isOpen && ds.source === "kaggle") {
|
|
152
|
-
output += `NOTE: This dataset
|
|
152
|
+
output += `NOTE: This dataset uses the Kaggle connector. Vesper can access it through server-managed credentials when configured, otherwise a Kaggle key is still required.\n\n`;
|
|
153
|
+
}
|
|
154
|
+
if (!isOpen && ds.source === "dataworld") {
|
|
155
|
+
output += `NOTE: This dataset uses the data.world connector. Vesper can access it through a server-managed token when configured.\n\n`;
|
|
153
156
|
}
|
|
154
157
|
// Description
|
|
155
158
|
if (ds.description) {
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import os from "os";
|
|
4
|
+
import path from "path";
|
|
5
|
+
function getHomeDir(buildDir) {
|
|
6
|
+
return os.homedir() || process.env.HOME || process.env.USERPROFILE || buildDir;
|
|
7
|
+
}
|
|
8
|
+
export function getVesperDataRoot(buildDir = process.cwd()) {
|
|
9
|
+
return path.join(getHomeDir(buildDir), ".vesper");
|
|
10
|
+
}
|
|
11
|
+
export function getManagedPythonPath(buildDir = process.cwd()) {
|
|
12
|
+
const dataRoot = getVesperDataRoot(buildDir);
|
|
13
|
+
return process.platform === "win32"
|
|
14
|
+
? path.join(dataRoot, ".venv", "Scripts", "python.exe")
|
|
15
|
+
: path.join(dataRoot, ".venv", "bin", "python");
|
|
16
|
+
}
|
|
17
|
+
function getFallbackPythonCommand() {
|
|
18
|
+
return process.platform === "win32" ? "py" : "python3";
|
|
19
|
+
}
|
|
20
|
+
export function resolvePythonCommand(buildDir = process.cwd()) {
|
|
21
|
+
const managedPython = getManagedPythonPath(buildDir);
|
|
22
|
+
if (fs.existsSync(managedPython)) {
|
|
23
|
+
return managedPython;
|
|
24
|
+
}
|
|
25
|
+
const envPython = process.env.VESPER_PYTHON;
|
|
26
|
+
if (envPython) {
|
|
27
|
+
return envPython;
|
|
28
|
+
}
|
|
29
|
+
const localCandidates = process.platform === "win32"
|
|
30
|
+
? [
|
|
31
|
+
path.resolve(buildDir, ".venv", "Scripts", "python.exe"),
|
|
32
|
+
path.resolve(buildDir, "..", ".venv", "Scripts", "python.exe")
|
|
33
|
+
]
|
|
34
|
+
: [
|
|
35
|
+
path.resolve(buildDir, ".venv", "bin", "python"),
|
|
36
|
+
path.resolve(buildDir, "..", ".venv", "bin", "python")
|
|
37
|
+
];
|
|
38
|
+
for (const candidate of localCandidates) {
|
|
39
|
+
if (fs.existsSync(candidate)) {
|
|
40
|
+
return candidate;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return getFallbackPythonCommand();
|
|
44
|
+
}
|
|
45
|
+
function runPythonCommand(pythonPath, args, timeoutMs = 300000) {
|
|
46
|
+
return new Promise((resolve, reject) => {
|
|
47
|
+
const proc = spawn(pythonPath, args, {
|
|
48
|
+
env: {
|
|
49
|
+
...process.env,
|
|
50
|
+
PYTHONIOENCODING: "utf-8",
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
let stdout = "";
|
|
54
|
+
let stderr = "";
|
|
55
|
+
const timer = setTimeout(() => {
|
|
56
|
+
proc.kill();
|
|
57
|
+
resolve({ code: 124, stdout, stderr: stderr || `Python command timed out after ${timeoutMs}ms` });
|
|
58
|
+
}, timeoutMs);
|
|
59
|
+
proc.stdout.on("data", (data) => {
|
|
60
|
+
stdout += data.toString();
|
|
61
|
+
});
|
|
62
|
+
proc.stderr.on("data", (data) => {
|
|
63
|
+
stderr += data.toString();
|
|
64
|
+
});
|
|
65
|
+
proc.on("close", (code) => {
|
|
66
|
+
clearTimeout(timer);
|
|
67
|
+
resolve({ code: code ?? 1, stdout, stderr });
|
|
68
|
+
});
|
|
69
|
+
proc.on("error", (error) => {
|
|
70
|
+
clearTimeout(timer);
|
|
71
|
+
reject(error);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
async function createManagedPythonEnv(buildDir) {
|
|
76
|
+
const dataRoot = getVesperDataRoot(buildDir);
|
|
77
|
+
const venvDir = path.join(dataRoot, ".venv");
|
|
78
|
+
const managedPython = getManagedPythonPath(buildDir);
|
|
79
|
+
if (fs.existsSync(managedPython)) {
|
|
80
|
+
return managedPython;
|
|
81
|
+
}
|
|
82
|
+
fs.mkdirSync(dataRoot, { recursive: true });
|
|
83
|
+
const bootstrapAttempts = process.platform === "win32"
|
|
84
|
+
? [
|
|
85
|
+
{ command: "py", args: ["-3", "-m", "venv", venvDir] },
|
|
86
|
+
{ command: "python", args: ["-m", "venv", venvDir] },
|
|
87
|
+
]
|
|
88
|
+
: [
|
|
89
|
+
{ command: "python3", args: ["-m", "venv", venvDir] },
|
|
90
|
+
{ command: "python", args: ["-m", "venv", venvDir] },
|
|
91
|
+
];
|
|
92
|
+
let lastError = "";
|
|
93
|
+
for (const attempt of bootstrapAttempts) {
|
|
94
|
+
try {
|
|
95
|
+
const result = await runPythonCommand(attempt.command, attempt.args, 180000);
|
|
96
|
+
if (result.code === 0 && fs.existsSync(managedPython)) {
|
|
97
|
+
await runPythonCommand(managedPython, ["-m", "pip", "install", "--disable-pip-version-check", "--upgrade", "pip"], 300000);
|
|
98
|
+
return managedPython;
|
|
99
|
+
}
|
|
100
|
+
lastError = (result.stderr || result.stdout || "Unknown venv creation error").trim();
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
lastError = error?.message || String(error);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
throw new Error(`Failed to create Vesper Python environment. ${lastError}`.trim());
|
|
107
|
+
}
|
|
108
|
+
export async function ensurePythonPackages(buildDir, requirements) {
|
|
109
|
+
const pythonPath = await createManagedPythonEnv(buildDir).catch(() => resolvePythonCommand(buildDir));
|
|
110
|
+
const missing = [];
|
|
111
|
+
for (const requirement of requirements) {
|
|
112
|
+
const check = await runPythonCommand(pythonPath, [
|
|
113
|
+
"-c",
|
|
114
|
+
`import importlib.util,sys; sys.exit(0 if importlib.util.find_spec(${JSON.stringify(requirement.module)}) else 1)`
|
|
115
|
+
], 20000);
|
|
116
|
+
if (check.code !== 0) {
|
|
117
|
+
missing.push(requirement);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (missing.length === 0) {
|
|
121
|
+
return pythonPath;
|
|
122
|
+
}
|
|
123
|
+
const packages = [...new Set(missing.map(requirement => requirement.packageName))];
|
|
124
|
+
const install = await runPythonCommand(pythonPath, ["-m", "pip", "install", "--disable-pip-version-check", ...packages], 600000);
|
|
125
|
+
if (install.code !== 0) {
|
|
126
|
+
const details = (install.stderr || install.stdout || "Unknown pip install error").trim();
|
|
127
|
+
throw new Error(`Failed to install Python packages (${packages.join(", ")}). ${details}`);
|
|
128
|
+
}
|
|
129
|
+
return pythonPath;
|
|
130
|
+
}
|
package/package.json
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vespermcp/mcp-server",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.22",
|
|
4
4
|
"description": "AI-powered dataset discovery, quality analysis, and preparation MCP server with multimodal support (text, image, audio, video)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "build/index.js",
|
|
7
7
|
"bin": {
|
|
8
|
-
"
|
|
9
|
-
"vespermcp": "./build/index.js",
|
|
10
|
-
"vesper-wizard": "scripts/wizard.js"
|
|
8
|
+
"vesper-wizard": "wizard.cjs"
|
|
11
9
|
},
|
|
12
10
|
"files": [
|
|
13
11
|
"build/**/*",
|
|
14
12
|
"src/python/**/*",
|
|
13
|
+
"wizard.cjs",
|
|
15
14
|
"scripts/**/*",
|
|
16
15
|
"README.md",
|
|
17
16
|
"LICENSE",
|
|
@@ -31,6 +30,7 @@
|
|
|
31
30
|
"fuse": "node build/index.js fuse",
|
|
32
31
|
"discover": "node build/index.js discover",
|
|
33
32
|
"download": "node build/index.js download",
|
|
33
|
+
"export": "node build/index.js export",
|
|
34
34
|
"config": "node build/index.js config",
|
|
35
35
|
"test-fusion-engine": "py src/python/test_fusion_engine.py",
|
|
36
36
|
"setup": "node build/index.js --setup",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"license": "MIT",
|
|
60
60
|
"repository": {
|
|
61
61
|
"type": "git",
|
|
62
|
-
"url": "https://github.com/vesper/mcp-server"
|
|
62
|
+
"url": "git+https://github.com/vesper/mcp-server.git"
|
|
63
63
|
},
|
|
64
64
|
"engines": {
|
|
65
65
|
"node": ">=18.0.0",
|
|
@@ -68,6 +68,8 @@
|
|
|
68
68
|
"dependencies": {
|
|
69
69
|
"@huggingface/hub": "^2.7.1",
|
|
70
70
|
"@modelcontextprotocol/sdk": "^1.25.2",
|
|
71
|
+
"@polar-sh/nextjs": "^0.9.4",
|
|
72
|
+
"@supabase/supabase-js": "^2.98.0",
|
|
71
73
|
"@xenova/transformers": "^2.17.2",
|
|
72
74
|
"adm-zip": "^0.5.16",
|
|
73
75
|
"ajv": "^8.17.1",
|
package/scripts/postinstall.cjs
CHANGED
|
@@ -2,13 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
const { execSync } = require('child_process');
|
|
4
4
|
const fs = require('fs');
|
|
5
|
+
const os = require('os');
|
|
5
6
|
const path = require('path');
|
|
6
7
|
|
|
7
8
|
console.log('\nš Setting up Vesper MCP Server...\n');
|
|
8
9
|
|
|
10
|
+
function getPythonBootstrapCommand() {
|
|
11
|
+
const attempts = process.platform === 'win32'
|
|
12
|
+
? ['py -3', 'python']
|
|
13
|
+
: ['python3', 'python'];
|
|
14
|
+
|
|
15
|
+
for (const command of attempts) {
|
|
16
|
+
try {
|
|
17
|
+
execSync(`${command} --version`, { stdio: 'pipe' });
|
|
18
|
+
return command;
|
|
19
|
+
} catch {
|
|
20
|
+
// try next command
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
|
|
9
27
|
// 1. Check for Python
|
|
28
|
+
const pythonBootstrap = getPythonBootstrapCommand();
|
|
10
29
|
try {
|
|
11
|
-
|
|
30
|
+
if (!pythonBootstrap) {
|
|
31
|
+
throw new Error('Python not found');
|
|
32
|
+
}
|
|
12
33
|
console.log('ā
Python found');
|
|
13
34
|
} catch (e) {
|
|
14
35
|
console.warn('ā ļø Python not found. Please install Python 3.8+ for full functionality.');
|
|
@@ -16,36 +37,15 @@ try {
|
|
|
16
37
|
process.exit(0); // Don't fail installation
|
|
17
38
|
}
|
|
18
39
|
|
|
19
|
-
|
|
20
|
-
console.log('\nš¦ Installing Python dependencies...');
|
|
21
|
-
const pythonPackages = [
|
|
22
|
-
'opencv-python',
|
|
23
|
-
'pillow',
|
|
24
|
-
'numpy',
|
|
25
|
-
'librosa',
|
|
26
|
-
'soundfile',
|
|
27
|
-
'aiohttp',
|
|
28
|
-
'aiofiles',
|
|
29
|
-
'datasets',
|
|
30
|
-
'webdataset',
|
|
31
|
-
'kaggle'
|
|
32
|
-
];
|
|
33
|
-
|
|
34
|
-
try {
|
|
35
|
-
execSync(`python -m pip install ${pythonPackages.join(' ')}`, {
|
|
36
|
-
stdio: 'inherit',
|
|
37
|
-
timeout: 120000 // 2 minutes timeout
|
|
38
|
-
});
|
|
39
|
-
console.log('ā
Python dependencies installed');
|
|
40
|
-
} catch (e) {
|
|
41
|
-
console.warn('ā ļø Failed to install some Python dependencies.');
|
|
42
|
-
console.warn(' You may need to install them manually:');
|
|
43
|
-
console.warn(` pip install ${pythonPackages.join(' ')}\n`);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// 3. Create data directories
|
|
47
|
-
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
40
|
+
const homeDir = os.homedir() || process.env.HOME || process.env.USERPROFILE;
|
|
48
41
|
const vesperDataDir = path.join(homeDir, '.vesper');
|
|
42
|
+
const managedVenvDir = path.join(vesperDataDir, '.venv');
|
|
43
|
+
const managedPython = process.platform === 'win32'
|
|
44
|
+
? path.join(managedVenvDir, 'Scripts', 'python.exe')
|
|
45
|
+
: path.join(managedVenvDir, 'bin', 'python');
|
|
46
|
+
const requirementsPath = path.resolve(__dirname, '..', 'src', 'python', 'requirements.txt');
|
|
47
|
+
|
|
48
|
+
// 2. Create data directories
|
|
49
49
|
const dirs = [
|
|
50
50
|
vesperDataDir,
|
|
51
51
|
path.join(vesperDataDir, 'data'),
|
|
@@ -62,7 +62,63 @@ dirs.forEach(dir => {
|
|
|
62
62
|
|
|
63
63
|
console.log(`ā
Data directories created at ${vesperDataDir}`);
|
|
64
64
|
|
|
65
|
-
//
|
|
65
|
+
// 3. Create a managed Vesper Python environment
|
|
66
|
+
console.log('\nš Preparing managed Python environment...');
|
|
67
|
+
try {
|
|
68
|
+
if (!fs.existsSync(managedPython)) {
|
|
69
|
+
execSync(`${pythonBootstrap} -m venv "${managedVenvDir}"`, {
|
|
70
|
+
stdio: 'inherit',
|
|
71
|
+
timeout: 180000,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
console.log(`ā
Managed Python ready at ${managedVenvDir}`);
|
|
75
|
+
} catch (e) {
|
|
76
|
+
console.warn('ā ļø Failed to create the managed Vesper Python environment.');
|
|
77
|
+
console.warn(` Vesper will fall back to PATH Python and may need to self-heal at runtime. ${(e && e.message) || ''}`.trim());
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// 4. Install Python dependencies into the managed environment
|
|
81
|
+
console.log('\nš¦ Installing Python dependencies...');
|
|
82
|
+
const pythonPackages = [
|
|
83
|
+
'opencv-python',
|
|
84
|
+
'pillow',
|
|
85
|
+
'librosa',
|
|
86
|
+
'soundfile',
|
|
87
|
+
'pyarrow'
|
|
88
|
+
];
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
const targetPython = fs.existsSync(managedPython) ? `"${managedPython}"` : pythonBootstrap;
|
|
92
|
+
execSync(`${targetPython} -m pip install --disable-pip-version-check --upgrade pip`, {
|
|
93
|
+
stdio: 'inherit',
|
|
94
|
+
timeout: 180000,
|
|
95
|
+
});
|
|
96
|
+
execSync(`${targetPython} -m pip install --disable-pip-version-check -r "${requirementsPath}" ${pythonPackages.join(' ')}`, {
|
|
97
|
+
stdio: 'inherit',
|
|
98
|
+
timeout: 600000,
|
|
99
|
+
});
|
|
100
|
+
console.log('ā
Python dependencies installed');
|
|
101
|
+
} catch (e) {
|
|
102
|
+
console.warn('ā ļø Failed to install some Python dependencies.');
|
|
103
|
+
console.warn(' You may need to install them manually into the Vesper runtime:');
|
|
104
|
+
console.warn(` ${fs.existsSync(managedPython) ? managedPython : pythonBootstrap} -m pip install -r "${requirementsPath}" ${pythonPackages.join(' ')}\n`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// 5. Rebuild better-sqlite3 for current Node.js version
|
|
108
|
+
console.log('\nš§ Rebuilding native modules for current Node.js...');
|
|
109
|
+
try {
|
|
110
|
+
execSync('npm rebuild better-sqlite3', {
|
|
111
|
+
stdio: 'pipe',
|
|
112
|
+
timeout: 60000,
|
|
113
|
+
cwd: path.resolve(__dirname, '..')
|
|
114
|
+
});
|
|
115
|
+
console.log('ā
Native modules rebuilt successfully');
|
|
116
|
+
} catch (e) {
|
|
117
|
+
console.warn('ā ļø Could not rebuild better-sqlite3: ' + (e.message || e));
|
|
118
|
+
console.warn(' If you see ERR_DLOPEN_FAILED, run: npm rebuild better-sqlite3');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// 6. Auto-configure Claude Desktop (Best Effort)
|
|
66
122
|
console.log('\nāļø Attempting to auto-configure Claude Desktop...');
|
|
67
123
|
|
|
68
124
|
function getClaudeConfigPath() {
|