@nimblebrain/mpak 0.0.1-beta.1 → 0.0.1-beta.3
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/.claude/settings.local.json +17 -0
- package/.github/workflows/ci.yml +27 -0
- package/CLAUDE.md +2 -0
- package/README.md +41 -0
- package/dist/commands/packages/run.d.ts +8 -0
- package/dist/commands/packages/run.d.ts.map +1 -0
- package/dist/commands/packages/run.js +216 -0
- package/dist/commands/packages/run.js.map +1 -0
- package/dist/commands/packages/show.d.ts.map +1 -1
- package/dist/commands/packages/show.js +0 -12
- package/dist/commands/packages/show.js.map +1 -1
- package/dist/index.js +0 -3
- package/dist/index.js.map +1 -1
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +9 -0
- package/dist/program.js.map +1 -1
- package/package.json +13 -7
- package/src/commands/packages/run.ts +281 -0
- package/src/commands/packages/show.ts +2 -12
- package/src/index.ts +0 -4
- package/src/lib/api/schema.d.ts +43 -71
- package/src/program.ts +10 -0
- package/test/integration/registry-client.test.ts +180 -0
- package/tsconfig.check.json +9 -0
- package/vitest.config.ts +2 -1
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(node dist/index.js:*)",
|
|
5
|
+
"Bash(npm test:*)",
|
|
6
|
+
"Bash(npm run build:*)",
|
|
7
|
+
"Bash(npm run test:all:*)",
|
|
8
|
+
"Bash(git add:*)",
|
|
9
|
+
"Bash(git commit:*)",
|
|
10
|
+
"Bash(npm version:*)",
|
|
11
|
+
"Bash(npm publish:*)",
|
|
12
|
+
"Bash(git push)",
|
|
13
|
+
"Bash(git tag:*)",
|
|
14
|
+
"Bash(git push:*)"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
|
|
16
|
+
- uses: actions/setup-node@v4
|
|
17
|
+
with:
|
|
18
|
+
node-version: '20'
|
|
19
|
+
cache: 'npm'
|
|
20
|
+
|
|
21
|
+
- run: npm ci
|
|
22
|
+
|
|
23
|
+
- run: npm run build
|
|
24
|
+
|
|
25
|
+
- run: npm run typecheck
|
|
26
|
+
|
|
27
|
+
- run: npm run test:all
|
package/CLAUDE.md
CHANGED
|
@@ -16,6 +16,7 @@ This is a standalone CLI that uses only the public v1 API. It has no dependencie
|
|
|
16
16
|
| `src/commands/packages/search.ts` | Search command implementation |
|
|
17
17
|
| `src/commands/packages/show.ts` | Show/info command implementation |
|
|
18
18
|
| `src/commands/packages/pull.ts` | Pull/install command implementation |
|
|
19
|
+
| `src/commands/packages/run.ts` | Run command implementation (caching, extraction, execution) |
|
|
19
20
|
| `src/utils/config-manager.ts` | Config file handling (~/.mpak/config.json) |
|
|
20
21
|
|
|
21
22
|
### Type Generation
|
|
@@ -102,6 +103,7 @@ npm run typecheck
|
|
|
102
103
|
| `info <package>` | Alias for show |
|
|
103
104
|
| `pull <package>` | Download a bundle |
|
|
104
105
|
| `install <package>` | Alias for pull |
|
|
106
|
+
| `run <package>` | Run an MCP server (pulls, caches, executes) |
|
|
105
107
|
|
|
106
108
|
## Design Decisions
|
|
107
109
|
|
package/README.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# mpak CLI
|
|
2
2
|
|
|
3
|
+
[](https://github.com/NimbleBrainInc/mpak-cli/actions/workflows/ci.yml)
|
|
4
|
+
[](https://opensource.org/licenses/Apache-2.0)
|
|
5
|
+
[](https://www.npmjs.com/package/@nimblebrain/mpak)
|
|
6
|
+
[](https://nodejs.org)
|
|
7
|
+
[](https://www.typescriptlang.org/)
|
|
8
|
+
[](https://www.nimblebrain.ai/discord?utm_source=github&utm_medium=readme&utm_campaign=mpak-cli&utm_content=discord-badge)
|
|
9
|
+
|
|
3
10
|
CLI for discovering and downloading MCPB bundles from the mpak registry.
|
|
4
11
|
|
|
5
12
|
## Installation
|
|
@@ -31,6 +38,7 @@ mpak pull @owner/my-server@1.0.0 # specific version
|
|
|
31
38
|
| `info <package>` | Alias for show |
|
|
32
39
|
| `pull <package>` | Download a bundle |
|
|
33
40
|
| `install <package>` | Alias for pull |
|
|
41
|
+
| `run <package>` | Run an MCP server from the registry |
|
|
34
42
|
|
|
35
43
|
### search
|
|
36
44
|
|
|
@@ -92,6 +100,39 @@ Options:
|
|
|
92
100
|
- `--arch <arch>` - Target architecture: x64, arm64
|
|
93
101
|
- `--json` - Output download info as JSON (doesn't download)
|
|
94
102
|
|
|
103
|
+
### run
|
|
104
|
+
|
|
105
|
+
Run an MCP server directly from the registry. Bundles are cached locally for fast subsequent runs.
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
# Run latest version
|
|
109
|
+
mpak run @nimblebraininc/echo
|
|
110
|
+
|
|
111
|
+
# Run specific version
|
|
112
|
+
mpak run @nimblebraininc/echo@1.0.0
|
|
113
|
+
|
|
114
|
+
# Force re-download (update cache)
|
|
115
|
+
mpak run @nimblebraininc/echo --update
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Options:
|
|
119
|
+
- `--update` - Force re-download even if cached
|
|
120
|
+
|
|
121
|
+
**Claude Desktop Integration:**
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"mcpServers": {
|
|
126
|
+
"echo": {
|
|
127
|
+
"command": "mpak",
|
|
128
|
+
"args": ["run", "@nimblebraininc/echo"]
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Bundles are cached in `~/.mpak/cache/` and automatically extracted on first run.
|
|
135
|
+
|
|
95
136
|
## Configuration
|
|
96
137
|
|
|
97
138
|
Configuration is stored in `~/.mpak/config.json`:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/commands/packages/run.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAiID;;GAEG;AACH,wBAAsB,SAAS,CAC7B,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,IAAI,CAAC,CAyIf"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { spawn, spawnSync } from 'child_process';
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync } from 'fs';
|
|
3
|
+
import { homedir } from 'os';
|
|
4
|
+
import { join, dirname } from 'path';
|
|
5
|
+
import { RegistryClient } from '../../lib/api/registry-client.js';
|
|
6
|
+
/**
|
|
7
|
+
* Parse package specification into name and version
|
|
8
|
+
*/
|
|
9
|
+
function parsePackageSpec(spec) {
|
|
10
|
+
const lastAtIndex = spec.lastIndexOf('@');
|
|
11
|
+
if (lastAtIndex <= 0) {
|
|
12
|
+
return { name: spec };
|
|
13
|
+
}
|
|
14
|
+
const name = spec.substring(0, lastAtIndex);
|
|
15
|
+
const version = spec.substring(lastAtIndex + 1);
|
|
16
|
+
if (!name.startsWith('@')) {
|
|
17
|
+
return { name: spec };
|
|
18
|
+
}
|
|
19
|
+
return { name, version };
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Get cache directory for a package
|
|
23
|
+
*/
|
|
24
|
+
function getCacheDir(packageName) {
|
|
25
|
+
const cacheBase = join(homedir(), '.mpak', 'cache');
|
|
26
|
+
// @scope/name -> scope/name
|
|
27
|
+
const safeName = packageName.replace('@', '').replace('/', '-');
|
|
28
|
+
return join(cacheBase, safeName);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Read cache metadata
|
|
32
|
+
*/
|
|
33
|
+
function getCacheMetadata(cacheDir) {
|
|
34
|
+
const metaPath = join(cacheDir, '.mpak-meta.json');
|
|
35
|
+
if (!existsSync(metaPath)) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
return JSON.parse(readFileSync(metaPath, 'utf8'));
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Write cache metadata
|
|
47
|
+
*/
|
|
48
|
+
function writeCacheMetadata(cacheDir, metadata) {
|
|
49
|
+
const metaPath = join(cacheDir, '.mpak-meta.json');
|
|
50
|
+
writeFileSync(metaPath, JSON.stringify(metadata, null, 2));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Extract ZIP file to directory (simple implementation without external deps)
|
|
54
|
+
*/
|
|
55
|
+
async function extractZip(zipPath, destDir) {
|
|
56
|
+
// Use native unzip command (available on macOS, Linux, and Windows with WSL)
|
|
57
|
+
const { execSync } = await import('child_process');
|
|
58
|
+
// Ensure destination exists
|
|
59
|
+
mkdirSync(destDir, { recursive: true });
|
|
60
|
+
try {
|
|
61
|
+
execSync(`unzip -o -q "${zipPath}" -d "${destDir}"`, { stdio: 'pipe' });
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
throw new Error(`Failed to extract bundle: ${error.message}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Read manifest from extracted bundle
|
|
69
|
+
*/
|
|
70
|
+
function readManifest(cacheDir) {
|
|
71
|
+
const manifestPath = join(cacheDir, 'manifest.json');
|
|
72
|
+
if (!existsSync(manifestPath)) {
|
|
73
|
+
throw new Error(`Manifest not found in bundle: ${manifestPath}`);
|
|
74
|
+
}
|
|
75
|
+
return JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Resolve placeholders in args (e.g., ${__dirname})
|
|
79
|
+
*/
|
|
80
|
+
function resolveArgs(args, cacheDir) {
|
|
81
|
+
return args.map(arg => arg.replace(/\$\{__dirname\}/g, cacheDir));
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Find Python executable (tries python3 first, then python)
|
|
85
|
+
*/
|
|
86
|
+
function findPythonCommand() {
|
|
87
|
+
// Try python3 first (preferred on macOS/Linux)
|
|
88
|
+
const result = spawnSync('python3', ['--version'], { stdio: 'pipe' });
|
|
89
|
+
if (result.status === 0) {
|
|
90
|
+
return 'python3';
|
|
91
|
+
}
|
|
92
|
+
// Fall back to python
|
|
93
|
+
return 'python';
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Run a package from the registry
|
|
97
|
+
*/
|
|
98
|
+
export async function handleRun(packageSpec, options = {}) {
|
|
99
|
+
const { name, version: requestedVersion } = parsePackageSpec(packageSpec);
|
|
100
|
+
const client = new RegistryClient();
|
|
101
|
+
const platform = RegistryClient.detectPlatform();
|
|
102
|
+
const cacheDir = getCacheDir(name);
|
|
103
|
+
let needsPull = true;
|
|
104
|
+
let cachedMeta = getCacheMetadata(cacheDir);
|
|
105
|
+
// Check if we have a cached version
|
|
106
|
+
if (cachedMeta && !options.update) {
|
|
107
|
+
if (requestedVersion) {
|
|
108
|
+
// Specific version requested - check if cached version matches
|
|
109
|
+
needsPull = cachedMeta.version !== requestedVersion;
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
// Latest requested - use cache (user can --update to refresh)
|
|
113
|
+
needsPull = false;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (needsPull) {
|
|
117
|
+
// Fetch download info
|
|
118
|
+
const downloadInfo = await client.getDownloadInfo(name, requestedVersion, platform);
|
|
119
|
+
const bundle = downloadInfo.bundle;
|
|
120
|
+
// Check if cached version is already the latest
|
|
121
|
+
if (cachedMeta && cachedMeta.version === bundle.version && !options.update) {
|
|
122
|
+
needsPull = false;
|
|
123
|
+
}
|
|
124
|
+
if (needsPull) {
|
|
125
|
+
// Download to temp file
|
|
126
|
+
const tempPath = join(homedir(), '.mpak', 'tmp', `${Date.now()}.mcpb`);
|
|
127
|
+
mkdirSync(dirname(tempPath), { recursive: true });
|
|
128
|
+
process.stderr.write(`=> Pulling ${name}@${bundle.version}...\n`);
|
|
129
|
+
await client.downloadBundle(downloadInfo.url, tempPath);
|
|
130
|
+
// Clear old cache and extract
|
|
131
|
+
const { rmSync } = await import('fs');
|
|
132
|
+
if (existsSync(cacheDir)) {
|
|
133
|
+
rmSync(cacheDir, { recursive: true, force: true });
|
|
134
|
+
}
|
|
135
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
136
|
+
await extractZip(tempPath, cacheDir);
|
|
137
|
+
// Write metadata
|
|
138
|
+
writeCacheMetadata(cacheDir, {
|
|
139
|
+
version: bundle.version,
|
|
140
|
+
pulledAt: new Date().toISOString(),
|
|
141
|
+
platform: bundle.platform,
|
|
142
|
+
});
|
|
143
|
+
// Cleanup temp file
|
|
144
|
+
rmSync(tempPath, { force: true });
|
|
145
|
+
process.stderr.write(`=> Cached ${name}@${bundle.version}\n`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// Read manifest and execute
|
|
149
|
+
const manifest = readManifest(cacheDir);
|
|
150
|
+
const { type, entry_point, mcp_config } = manifest.server;
|
|
151
|
+
let command;
|
|
152
|
+
let args;
|
|
153
|
+
let env = { ...process.env, ...mcp_config.env };
|
|
154
|
+
switch (type) {
|
|
155
|
+
case 'binary': {
|
|
156
|
+
// For binary, the entry_point is the executable path relative to bundle
|
|
157
|
+
command = join(cacheDir, entry_point);
|
|
158
|
+
args = resolveArgs(mcp_config.args || [], cacheDir);
|
|
159
|
+
// Ensure binary is executable
|
|
160
|
+
try {
|
|
161
|
+
chmodSync(command, 0o755);
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
// Ignore chmod errors on Windows
|
|
165
|
+
}
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
case 'node': {
|
|
169
|
+
command = mcp_config.command || 'node';
|
|
170
|
+
// Use mcp_config.args directly if provided, otherwise fall back to entry_point
|
|
171
|
+
if (mcp_config.args && mcp_config.args.length > 0) {
|
|
172
|
+
args = resolveArgs(mcp_config.args, cacheDir);
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
args = [join(cacheDir, entry_point)];
|
|
176
|
+
}
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
case 'python': {
|
|
180
|
+
// Use manifest command if specified, otherwise auto-detect python
|
|
181
|
+
command = mcp_config.command === 'python' ? findPythonCommand() : (mcp_config.command || findPythonCommand());
|
|
182
|
+
// Use mcp_config.args directly if provided, otherwise fall back to entry_point
|
|
183
|
+
if (mcp_config.args && mcp_config.args.length > 0) {
|
|
184
|
+
args = resolveArgs(mcp_config.args, cacheDir);
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
args = [join(cacheDir, entry_point)];
|
|
188
|
+
}
|
|
189
|
+
// Set PYTHONPATH to deps/ directory for dependency resolution
|
|
190
|
+
const depsDir = join(cacheDir, 'deps');
|
|
191
|
+
const existingPythonPath = process.env.PYTHONPATH;
|
|
192
|
+
env.PYTHONPATH = existingPythonPath ? `${depsDir}:${existingPythonPath}` : depsDir;
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
default:
|
|
196
|
+
throw new Error(`Unsupported server type: ${type}`);
|
|
197
|
+
}
|
|
198
|
+
// Spawn with stdio passthrough for MCP
|
|
199
|
+
const child = spawn(command, args, {
|
|
200
|
+
stdio: ['inherit', 'inherit', 'inherit'],
|
|
201
|
+
env,
|
|
202
|
+
cwd: cacheDir,
|
|
203
|
+
});
|
|
204
|
+
// Forward signals
|
|
205
|
+
process.on('SIGINT', () => child.kill('SIGINT'));
|
|
206
|
+
process.on('SIGTERM', () => child.kill('SIGTERM'));
|
|
207
|
+
// Wait for exit
|
|
208
|
+
child.on('exit', (code) => {
|
|
209
|
+
process.exit(code ?? 0);
|
|
210
|
+
});
|
|
211
|
+
child.on('error', (error) => {
|
|
212
|
+
process.stderr.write(`=> Failed to start server: ${error.message}\n`);
|
|
213
|
+
process.exit(1);
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/commands/packages/run.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"show.d.ts","sourceRoot":"","sources":["../../../src/commands/packages/show.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"show.d.ts","sourceRoot":"","sources":["../../../src/commands/packages/show.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,IAAI,CAAC,CAmHf"}
|
|
@@ -52,18 +52,6 @@ export async function handleShow(packageName, options = {}) {
|
|
|
52
52
|
console.log(` Downloads: ${bundle.downloads.toLocaleString()}`);
|
|
53
53
|
console.log(` Published: ${new Date(bundle.published_at).toLocaleDateString()}`);
|
|
54
54
|
console.log();
|
|
55
|
-
// GitHub info
|
|
56
|
-
if (bundle.github) {
|
|
57
|
-
console.log('GitHub:');
|
|
58
|
-
console.log(` Repository: ${bundle.github.repo}`);
|
|
59
|
-
if (bundle.github.stars != null)
|
|
60
|
-
console.log(` Stars: ${bundle.github.stars}`);
|
|
61
|
-
if (bundle.github.forks != null)
|
|
62
|
-
console.log(` Forks: ${bundle.github.forks}`);
|
|
63
|
-
if (bundle.github.watchers != null)
|
|
64
|
-
console.log(` Watchers: ${bundle.github.watchers}`);
|
|
65
|
-
console.log();
|
|
66
|
-
}
|
|
67
55
|
// Tools
|
|
68
56
|
if (bundle.tools && bundle.tools.length > 0) {
|
|
69
57
|
console.log(`Tools (${bundle.tools.length}):`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"show.js","sourceRoot":"","sources":["../../../src/commands/packages/show.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"show.js","sourceRoot":"","sources":["../../../src/commands/packages/show.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { config } from 'dotenv';
|
|
3
2
|
import { createProgram } from './program.js';
|
|
4
3
|
import { handleError } from './utils/errors.js';
|
|
5
|
-
// Load environment variables from .env file
|
|
6
|
-
config();
|
|
7
4
|
async function main() {
|
|
8
5
|
const program = createProgram();
|
|
9
6
|
await program.parseAsync(process.argv);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,KAAK,UAAU,IAAI;IACjB,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;IAChC,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC"}
|
package/dist/program.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAyEvC"}
|
package/dist/program.js
CHANGED
|
@@ -3,6 +3,7 @@ import { getVersion } from './utils/version.js';
|
|
|
3
3
|
import { handleSearch } from './commands/packages/search.js';
|
|
4
4
|
import { handleShow } from './commands/packages/show.js';
|
|
5
5
|
import { handlePull } from './commands/packages/pull.js';
|
|
6
|
+
import { handleRun } from './commands/packages/run.js';
|
|
6
7
|
/**
|
|
7
8
|
* Creates and configures the CLI program
|
|
8
9
|
*
|
|
@@ -64,6 +65,14 @@ export function createProgram() {
|
|
|
64
65
|
.action(async (packageSpec, options) => {
|
|
65
66
|
await handlePull(packageSpec, options);
|
|
66
67
|
});
|
|
68
|
+
// Run command
|
|
69
|
+
program
|
|
70
|
+
.command('run <package>')
|
|
71
|
+
.description('Run an MCP server from the registry (e.g., @scope/name or @scope/name@1.0.0)')
|
|
72
|
+
.option('--update', 'Force re-download even if cached')
|
|
73
|
+
.action(async (packageSpec, options) => {
|
|
74
|
+
await handleRun(packageSpec, options);
|
|
75
|
+
});
|
|
67
76
|
return program;
|
|
68
77
|
}
|
|
69
78
|
//# sourceMappingURL=program.js.map
|
package/dist/program.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"program.js","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"program.js","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nimblebrain/mpak",
|
|
3
|
-
"version": "0.0.1-beta.
|
|
3
|
+
"version": "0.0.1-beta.3",
|
|
4
4
|
"description": "CLI for downloading MCPB bundles from the mpak registry",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
|
-
"mpak": "
|
|
8
|
+
"mpak": "dist/index.js"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"build": "tsc",
|
|
@@ -15,10 +15,14 @@
|
|
|
15
15
|
"lint:fix": "eslint src --fix",
|
|
16
16
|
"prepublishOnly": "npm run build",
|
|
17
17
|
"start": "node dist/index.js",
|
|
18
|
-
"test": "vitest",
|
|
18
|
+
"test": "vitest --run src",
|
|
19
|
+
"test:unit": "vitest --run src",
|
|
20
|
+
"test:integration": "vitest --run test/integration",
|
|
21
|
+
"test:all": "vitest --run",
|
|
22
|
+
"test:watch": "vitest",
|
|
19
23
|
"test:ui": "vitest --ui",
|
|
20
24
|
"test:coverage": "vitest --coverage",
|
|
21
|
-
"typecheck": "tsc
|
|
25
|
+
"typecheck": "tsc -p tsconfig.check.json"
|
|
22
26
|
},
|
|
23
27
|
"keywords": [
|
|
24
28
|
"mcp",
|
|
@@ -29,9 +33,11 @@
|
|
|
29
33
|
],
|
|
30
34
|
"author": "NimbleBrain Inc",
|
|
31
35
|
"license": "Apache-2.0",
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=18"
|
|
38
|
+
},
|
|
32
39
|
"dependencies": {
|
|
33
|
-
"commander": "^14.0.2"
|
|
34
|
-
"dotenv": "^17.2.3"
|
|
40
|
+
"commander": "^14.0.2"
|
|
35
41
|
},
|
|
36
42
|
"devDependencies": {
|
|
37
43
|
"@types/node": "^25.0.3",
|
|
@@ -45,4 +51,4 @@
|
|
|
45
51
|
"access": "public",
|
|
46
52
|
"registry": "https://registry.npmjs.org/"
|
|
47
53
|
}
|
|
48
|
-
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { spawn, spawnSync } from 'child_process';
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync } from 'fs';
|
|
3
|
+
import { homedir } from 'os';
|
|
4
|
+
import { join, dirname } from 'path';
|
|
5
|
+
import { RegistryClient } from '../../lib/api/registry-client.js';
|
|
6
|
+
|
|
7
|
+
export interface RunOptions {
|
|
8
|
+
update?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface McpConfig {
|
|
12
|
+
command: string;
|
|
13
|
+
args: string[];
|
|
14
|
+
env?: Record<string, string>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface McpbManifest {
|
|
18
|
+
manifest_version: string;
|
|
19
|
+
name: string;
|
|
20
|
+
version: string;
|
|
21
|
+
description: string;
|
|
22
|
+
server: {
|
|
23
|
+
type: 'node' | 'python' | 'binary';
|
|
24
|
+
entry_point: string;
|
|
25
|
+
mcp_config: McpConfig;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface CacheMetadata {
|
|
30
|
+
version: string;
|
|
31
|
+
pulledAt: string;
|
|
32
|
+
platform: { os: string; arch: string };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Parse package specification into name and version
|
|
37
|
+
*/
|
|
38
|
+
function parsePackageSpec(spec: string): { name: string; version?: string } {
|
|
39
|
+
const lastAtIndex = spec.lastIndexOf('@');
|
|
40
|
+
|
|
41
|
+
if (lastAtIndex <= 0) {
|
|
42
|
+
return { name: spec };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const name = spec.substring(0, lastAtIndex);
|
|
46
|
+
const version = spec.substring(lastAtIndex + 1);
|
|
47
|
+
|
|
48
|
+
if (!name.startsWith('@')) {
|
|
49
|
+
return { name: spec };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return { name, version };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get cache directory for a package
|
|
57
|
+
*/
|
|
58
|
+
function getCacheDir(packageName: string): string {
|
|
59
|
+
const cacheBase = join(homedir(), '.mpak', 'cache');
|
|
60
|
+
// @scope/name -> scope/name
|
|
61
|
+
const safeName = packageName.replace('@', '').replace('/', '-');
|
|
62
|
+
return join(cacheBase, safeName);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Read cache metadata
|
|
67
|
+
*/
|
|
68
|
+
function getCacheMetadata(cacheDir: string): CacheMetadata | null {
|
|
69
|
+
const metaPath = join(cacheDir, '.mpak-meta.json');
|
|
70
|
+
if (!existsSync(metaPath)) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
return JSON.parse(readFileSync(metaPath, 'utf8'));
|
|
75
|
+
} catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Write cache metadata
|
|
82
|
+
*/
|
|
83
|
+
function writeCacheMetadata(cacheDir: string, metadata: CacheMetadata): void {
|
|
84
|
+
const metaPath = join(cacheDir, '.mpak-meta.json');
|
|
85
|
+
writeFileSync(metaPath, JSON.stringify(metadata, null, 2));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Extract ZIP file to directory (simple implementation without external deps)
|
|
90
|
+
*/
|
|
91
|
+
async function extractZip(zipPath: string, destDir: string): Promise<void> {
|
|
92
|
+
// Use native unzip command (available on macOS, Linux, and Windows with WSL)
|
|
93
|
+
const { execSync } = await import('child_process');
|
|
94
|
+
|
|
95
|
+
// Ensure destination exists
|
|
96
|
+
mkdirSync(destDir, { recursive: true });
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
execSync(`unzip -o -q "${zipPath}" -d "${destDir}"`, { stdio: 'pipe' });
|
|
100
|
+
} catch (error: any) {
|
|
101
|
+
throw new Error(`Failed to extract bundle: ${error.message}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Read manifest from extracted bundle
|
|
107
|
+
*/
|
|
108
|
+
function readManifest(cacheDir: string): McpbManifest {
|
|
109
|
+
const manifestPath = join(cacheDir, 'manifest.json');
|
|
110
|
+
if (!existsSync(manifestPath)) {
|
|
111
|
+
throw new Error(`Manifest not found in bundle: ${manifestPath}`);
|
|
112
|
+
}
|
|
113
|
+
return JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Resolve placeholders in args (e.g., ${__dirname})
|
|
118
|
+
*/
|
|
119
|
+
function resolveArgs(args: string[], cacheDir: string): string[] {
|
|
120
|
+
return args.map(arg =>
|
|
121
|
+
arg.replace(/\$\{__dirname\}/g, cacheDir)
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Find Python executable (tries python3 first, then python)
|
|
127
|
+
*/
|
|
128
|
+
function findPythonCommand(): string {
|
|
129
|
+
// Try python3 first (preferred on macOS/Linux)
|
|
130
|
+
const result = spawnSync('python3', ['--version'], { stdio: 'pipe' });
|
|
131
|
+
if (result.status === 0) {
|
|
132
|
+
return 'python3';
|
|
133
|
+
}
|
|
134
|
+
// Fall back to python
|
|
135
|
+
return 'python';
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Run a package from the registry
|
|
140
|
+
*/
|
|
141
|
+
export async function handleRun(
|
|
142
|
+
packageSpec: string,
|
|
143
|
+
options: RunOptions = {}
|
|
144
|
+
): Promise<void> {
|
|
145
|
+
const { name, version: requestedVersion } = parsePackageSpec(packageSpec);
|
|
146
|
+
const client = new RegistryClient();
|
|
147
|
+
const platform = RegistryClient.detectPlatform();
|
|
148
|
+
const cacheDir = getCacheDir(name);
|
|
149
|
+
|
|
150
|
+
let needsPull = true;
|
|
151
|
+
let cachedMeta = getCacheMetadata(cacheDir);
|
|
152
|
+
|
|
153
|
+
// Check if we have a cached version
|
|
154
|
+
if (cachedMeta && !options.update) {
|
|
155
|
+
if (requestedVersion) {
|
|
156
|
+
// Specific version requested - check if cached version matches
|
|
157
|
+
needsPull = cachedMeta.version !== requestedVersion;
|
|
158
|
+
} else {
|
|
159
|
+
// Latest requested - use cache (user can --update to refresh)
|
|
160
|
+
needsPull = false;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (needsPull) {
|
|
165
|
+
// Fetch download info
|
|
166
|
+
const downloadInfo = await client.getDownloadInfo(name, requestedVersion, platform);
|
|
167
|
+
const bundle = downloadInfo.bundle;
|
|
168
|
+
|
|
169
|
+
// Check if cached version is already the latest
|
|
170
|
+
if (cachedMeta && cachedMeta.version === bundle.version && !options.update) {
|
|
171
|
+
needsPull = false;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (needsPull) {
|
|
175
|
+
// Download to temp file
|
|
176
|
+
const tempPath = join(homedir(), '.mpak', 'tmp', `${Date.now()}.mcpb`);
|
|
177
|
+
mkdirSync(dirname(tempPath), { recursive: true });
|
|
178
|
+
|
|
179
|
+
process.stderr.write(`=> Pulling ${name}@${bundle.version}...\n`);
|
|
180
|
+
await client.downloadBundle(downloadInfo.url, tempPath);
|
|
181
|
+
|
|
182
|
+
// Clear old cache and extract
|
|
183
|
+
const { rmSync } = await import('fs');
|
|
184
|
+
if (existsSync(cacheDir)) {
|
|
185
|
+
rmSync(cacheDir, { recursive: true, force: true });
|
|
186
|
+
}
|
|
187
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
188
|
+
|
|
189
|
+
await extractZip(tempPath, cacheDir);
|
|
190
|
+
|
|
191
|
+
// Write metadata
|
|
192
|
+
writeCacheMetadata(cacheDir, {
|
|
193
|
+
version: bundle.version,
|
|
194
|
+
pulledAt: new Date().toISOString(),
|
|
195
|
+
platform: bundle.platform,
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Cleanup temp file
|
|
199
|
+
rmSync(tempPath, { force: true });
|
|
200
|
+
|
|
201
|
+
process.stderr.write(`=> Cached ${name}@${bundle.version}\n`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Read manifest and execute
|
|
206
|
+
const manifest = readManifest(cacheDir);
|
|
207
|
+
const { type, entry_point, mcp_config } = manifest.server;
|
|
208
|
+
|
|
209
|
+
let command: string;
|
|
210
|
+
let args: string[];
|
|
211
|
+
let env: Record<string, string | undefined> = { ...process.env, ...mcp_config.env };
|
|
212
|
+
|
|
213
|
+
switch (type) {
|
|
214
|
+
case 'binary': {
|
|
215
|
+
// For binary, the entry_point is the executable path relative to bundle
|
|
216
|
+
command = join(cacheDir, entry_point);
|
|
217
|
+
args = resolveArgs(mcp_config.args || [], cacheDir);
|
|
218
|
+
|
|
219
|
+
// Ensure binary is executable
|
|
220
|
+
try {
|
|
221
|
+
chmodSync(command, 0o755);
|
|
222
|
+
} catch {
|
|
223
|
+
// Ignore chmod errors on Windows
|
|
224
|
+
}
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
case 'node': {
|
|
229
|
+
command = mcp_config.command || 'node';
|
|
230
|
+
// Use mcp_config.args directly if provided, otherwise fall back to entry_point
|
|
231
|
+
if (mcp_config.args && mcp_config.args.length > 0) {
|
|
232
|
+
args = resolveArgs(mcp_config.args, cacheDir);
|
|
233
|
+
} else {
|
|
234
|
+
args = [join(cacheDir, entry_point)];
|
|
235
|
+
}
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
case 'python': {
|
|
240
|
+
// Use manifest command if specified, otherwise auto-detect python
|
|
241
|
+
command = mcp_config.command === 'python' ? findPythonCommand() : (mcp_config.command || findPythonCommand());
|
|
242
|
+
|
|
243
|
+
// Use mcp_config.args directly if provided, otherwise fall back to entry_point
|
|
244
|
+
if (mcp_config.args && mcp_config.args.length > 0) {
|
|
245
|
+
args = resolveArgs(mcp_config.args, cacheDir);
|
|
246
|
+
} else {
|
|
247
|
+
args = [join(cacheDir, entry_point)];
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Set PYTHONPATH to deps/ directory for dependency resolution
|
|
251
|
+
const depsDir = join(cacheDir, 'deps');
|
|
252
|
+
const existingPythonPath = process.env.PYTHONPATH;
|
|
253
|
+
env.PYTHONPATH = existingPythonPath ? `${depsDir}:${existingPythonPath}` : depsDir;
|
|
254
|
+
break;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
default:
|
|
258
|
+
throw new Error(`Unsupported server type: ${type}`);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Spawn with stdio passthrough for MCP
|
|
262
|
+
const child = spawn(command, args, {
|
|
263
|
+
stdio: ['inherit', 'inherit', 'inherit'],
|
|
264
|
+
env,
|
|
265
|
+
cwd: cacheDir,
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
// Forward signals
|
|
269
|
+
process.on('SIGINT', () => child.kill('SIGINT'));
|
|
270
|
+
process.on('SIGTERM', () => child.kill('SIGTERM'));
|
|
271
|
+
|
|
272
|
+
// Wait for exit
|
|
273
|
+
child.on('exit', (code) => {
|
|
274
|
+
process.exit(code ?? 0);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
child.on('error', (error) => {
|
|
278
|
+
process.stderr.write(`=> Failed to start server: ${error.message}\n`);
|
|
279
|
+
process.exit(1);
|
|
280
|
+
});
|
|
281
|
+
}
|
|
@@ -65,19 +65,9 @@ export async function handleShow(
|
|
|
65
65
|
// Stats
|
|
66
66
|
console.log('Statistics:');
|
|
67
67
|
console.log(` Downloads: ${bundle.downloads.toLocaleString()}`);
|
|
68
|
-
console.log(` Published: ${new Date(bundle.published_at).toLocaleDateString()}`);
|
|
68
|
+
console.log(` Published: ${new Date(bundle.published_at as string).toLocaleDateString()}`);
|
|
69
69
|
console.log();
|
|
70
70
|
|
|
71
|
-
// GitHub info
|
|
72
|
-
if (bundle.github) {
|
|
73
|
-
console.log('GitHub:');
|
|
74
|
-
console.log(` Repository: ${bundle.github.repo}`);
|
|
75
|
-
if (bundle.github.stars != null) console.log(` Stars: ${bundle.github.stars}`);
|
|
76
|
-
if (bundle.github.forks != null) console.log(` Forks: ${bundle.github.forks}`);
|
|
77
|
-
if (bundle.github.watchers != null) console.log(` Watchers: ${bundle.github.watchers}`);
|
|
78
|
-
console.log();
|
|
79
|
-
}
|
|
80
|
-
|
|
81
71
|
// Tools
|
|
82
72
|
if (bundle.tools && bundle.tools.length > 0) {
|
|
83
73
|
console.log(`Tools (${bundle.tools.length}):`);
|
|
@@ -95,7 +85,7 @@ export async function handleShow(
|
|
|
95
85
|
console.log(`Versions (${versionsInfo.versions.length}):`);
|
|
96
86
|
const recentVersions = versionsInfo.versions.slice(0, 5);
|
|
97
87
|
for (const version of recentVersions) {
|
|
98
|
-
const date = new Date(version.published_at).toLocaleDateString();
|
|
88
|
+
const date = new Date(version.published_at as string).toLocaleDateString();
|
|
99
89
|
const downloads = version.downloads.toLocaleString();
|
|
100
90
|
const isLatest = version.version === versionsInfo.latest ? ' (latest)' : '';
|
|
101
91
|
const provTag = version.provenance ? ' 🔒' : '';
|
package/src/index.ts
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { config } from 'dotenv';
|
|
4
3
|
import { createProgram } from './program.js';
|
|
5
4
|
import { handleError } from './utils/errors.js';
|
|
6
5
|
|
|
7
|
-
// Load environment variables from .env file
|
|
8
|
-
config();
|
|
9
|
-
|
|
10
6
|
async function main() {
|
|
11
7
|
const program = createProgram();
|
|
12
8
|
await program.parseAsync(process.argv);
|
package/src/lib/api/schema.d.ts
CHANGED
|
@@ -51,8 +51,7 @@ export interface paths {
|
|
|
51
51
|
description?: string;
|
|
52
52
|
}[];
|
|
53
53
|
downloads: number;
|
|
54
|
-
|
|
55
|
-
published_at: string;
|
|
54
|
+
published_at: string | unknown;
|
|
56
55
|
verified: boolean;
|
|
57
56
|
provenance?: {
|
|
58
57
|
schema_version: string;
|
|
@@ -121,27 +120,19 @@ export interface paths {
|
|
|
121
120
|
description?: string;
|
|
122
121
|
}[];
|
|
123
122
|
downloads: number;
|
|
124
|
-
|
|
125
|
-
published_at: string;
|
|
123
|
+
published_at: string | unknown;
|
|
126
124
|
verified: boolean;
|
|
127
|
-
homepage?: string | null;
|
|
128
|
-
license?: string | null;
|
|
129
|
-
github?: {
|
|
130
|
-
repo: string;
|
|
131
|
-
stars?: number | null;
|
|
132
|
-
forks?: number | null;
|
|
133
|
-
watchers?: number | null;
|
|
134
|
-
} | null;
|
|
135
125
|
provenance?: {
|
|
136
126
|
schema_version: string;
|
|
137
127
|
provider: string;
|
|
138
128
|
repository: string;
|
|
139
129
|
sha: string;
|
|
140
130
|
} | null;
|
|
131
|
+
homepage?: string | null;
|
|
132
|
+
license?: string | null;
|
|
141
133
|
versions: {
|
|
142
134
|
version: string;
|
|
143
|
-
|
|
144
|
-
published_at: string;
|
|
135
|
+
published_at: string | unknown;
|
|
145
136
|
downloads: number;
|
|
146
137
|
}[];
|
|
147
138
|
};
|
|
@@ -188,15 +179,13 @@ export interface paths {
|
|
|
188
179
|
mimeType: string;
|
|
189
180
|
name: string;
|
|
190
181
|
version: string;
|
|
191
|
-
description
|
|
182
|
+
description: string | null;
|
|
192
183
|
bundles: {
|
|
193
|
-
mimeType: string;
|
|
184
|
+
mimeType: string | null;
|
|
194
185
|
digest: string;
|
|
195
186
|
size: number;
|
|
196
187
|
platform: {
|
|
197
|
-
/** @description Operating system (darwin, linux, win32, any) */
|
|
198
188
|
os: string;
|
|
199
|
-
/** @description Architecture (x64, arm64, any) */
|
|
200
189
|
arch: string;
|
|
201
190
|
};
|
|
202
191
|
urls: string[];
|
|
@@ -250,15 +239,12 @@ export interface paths {
|
|
|
250
239
|
version: string;
|
|
251
240
|
artifacts_count: number;
|
|
252
241
|
platforms: {
|
|
253
|
-
/** @description Operating system (darwin, linux, win32, any) */
|
|
254
242
|
os: string;
|
|
255
|
-
/** @description Architecture (x64, arm64, any) */
|
|
256
243
|
arch: string;
|
|
257
244
|
}[];
|
|
258
|
-
|
|
259
|
-
published_at: string;
|
|
245
|
+
published_at: string | unknown;
|
|
260
246
|
downloads: number;
|
|
261
|
-
publish_method
|
|
247
|
+
publish_method: string | null;
|
|
262
248
|
provenance?: {
|
|
263
249
|
schema_version: string;
|
|
264
250
|
provider: string;
|
|
@@ -309,14 +295,11 @@ export interface paths {
|
|
|
309
295
|
"application/json": {
|
|
310
296
|
name: string;
|
|
311
297
|
version: string;
|
|
312
|
-
|
|
313
|
-
published_at: string;
|
|
298
|
+
published_at: string | unknown;
|
|
314
299
|
downloads: number;
|
|
315
300
|
artifacts: {
|
|
316
301
|
platform: {
|
|
317
|
-
/** @description Operating system (darwin, linux, win32, any) */
|
|
318
302
|
os: string;
|
|
319
|
-
/** @description Architecture (x64, arm64, any) */
|
|
320
303
|
arch: string;
|
|
321
304
|
};
|
|
322
305
|
digest: string;
|
|
@@ -324,16 +307,19 @@ export interface paths {
|
|
|
324
307
|
download_url: string;
|
|
325
308
|
source_url?: string;
|
|
326
309
|
}[];
|
|
327
|
-
manifest
|
|
310
|
+
manifest: {
|
|
328
311
|
[key: string]: unknown;
|
|
329
312
|
};
|
|
330
313
|
release?: {
|
|
331
|
-
tag
|
|
332
|
-
url
|
|
333
|
-
}
|
|
334
|
-
publish_method
|
|
335
|
-
provenance
|
|
336
|
-
|
|
314
|
+
tag: string | null;
|
|
315
|
+
url: string | null;
|
|
316
|
+
};
|
|
317
|
+
publish_method: string | null;
|
|
318
|
+
provenance: {
|
|
319
|
+
schema_version: string;
|
|
320
|
+
provider: string;
|
|
321
|
+
repository: string;
|
|
322
|
+
sha: string;
|
|
337
323
|
} | null;
|
|
338
324
|
};
|
|
339
325
|
};
|
|
@@ -386,16 +372,13 @@ export interface paths {
|
|
|
386
372
|
name: string;
|
|
387
373
|
version: string;
|
|
388
374
|
platform: {
|
|
389
|
-
/** @description Operating system (darwin, linux, win32, any) */
|
|
390
375
|
os: string;
|
|
391
|
-
/** @description Architecture (x64, arm64, any) */
|
|
392
376
|
arch: string;
|
|
393
377
|
};
|
|
394
378
|
sha256: string;
|
|
395
379
|
size: number;
|
|
396
380
|
};
|
|
397
|
-
|
|
398
|
-
expires_at: string;
|
|
381
|
+
expires_at?: string;
|
|
399
382
|
};
|
|
400
383
|
};
|
|
401
384
|
};
|
|
@@ -425,7 +408,7 @@ export interface paths {
|
|
|
425
408
|
};
|
|
426
409
|
get?: never;
|
|
427
410
|
put?: never;
|
|
428
|
-
/** @description Announce a
|
|
411
|
+
/** @description Announce a single artifact for a bundle version from a GitHub release (OIDC only). Idempotent - can be called multiple times for different artifacts of the same version. */
|
|
429
412
|
post: {
|
|
430
413
|
parameters: {
|
|
431
414
|
query?: never;
|
|
@@ -436,14 +419,21 @@ export interface paths {
|
|
|
436
419
|
requestBody: {
|
|
437
420
|
content: {
|
|
438
421
|
"application/json": {
|
|
439
|
-
/** @description Package name (@scope/name) */
|
|
440
422
|
name: string;
|
|
441
|
-
/** @description Semantic version */
|
|
442
423
|
version: string;
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
424
|
+
manifest: {
|
|
425
|
+
[key: string]: unknown;
|
|
426
|
+
};
|
|
446
427
|
release_tag: string;
|
|
428
|
+
/** @default false */
|
|
429
|
+
prerelease: boolean;
|
|
430
|
+
artifact: {
|
|
431
|
+
filename: string;
|
|
432
|
+
os: string;
|
|
433
|
+
arch: string;
|
|
434
|
+
sha256: string;
|
|
435
|
+
size: number;
|
|
436
|
+
};
|
|
447
437
|
};
|
|
448
438
|
};
|
|
449
439
|
};
|
|
@@ -455,34 +445,16 @@ export interface paths {
|
|
|
455
445
|
};
|
|
456
446
|
content: {
|
|
457
447
|
"application/json": {
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
release: {
|
|
465
|
-
tag: string;
|
|
466
|
-
url: string;
|
|
448
|
+
package: string;
|
|
449
|
+
version: string;
|
|
450
|
+
artifact: {
|
|
451
|
+
os: string;
|
|
452
|
+
arch: string;
|
|
453
|
+
filename: string;
|
|
467
454
|
};
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
os: string;
|
|
472
|
-
/** @description Architecture (x64, arm64, any) */
|
|
473
|
-
arch: string;
|
|
474
|
-
};
|
|
475
|
-
digest: string;
|
|
476
|
-
size: number;
|
|
477
|
-
url: string;
|
|
478
|
-
source_url: string;
|
|
479
|
-
}[];
|
|
480
|
-
provenance: {
|
|
481
|
-
schema_version: string;
|
|
482
|
-
provider: string;
|
|
483
|
-
repository: string;
|
|
484
|
-
sha: string;
|
|
485
|
-
} | null;
|
|
455
|
+
total_artifacts: number;
|
|
456
|
+
/** @enum {string} */
|
|
457
|
+
status: "created" | "updated";
|
|
486
458
|
};
|
|
487
459
|
};
|
|
488
460
|
};
|
package/src/program.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { getVersion } from './utils/version.js';
|
|
|
3
3
|
import { handleSearch } from './commands/packages/search.js';
|
|
4
4
|
import { handleShow } from './commands/packages/show.js';
|
|
5
5
|
import { handlePull } from './commands/packages/pull.js';
|
|
6
|
+
import { handleRun } from './commands/packages/run.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Creates and configures the CLI program
|
|
@@ -72,5 +73,14 @@ export function createProgram(): Command {
|
|
|
72
73
|
await handlePull(packageSpec, options);
|
|
73
74
|
});
|
|
74
75
|
|
|
76
|
+
// Run command
|
|
77
|
+
program
|
|
78
|
+
.command('run <package>')
|
|
79
|
+
.description('Run an MCP server from the registry (e.g., @scope/name or @scope/name@1.0.0)')
|
|
80
|
+
.option('--update', 'Force re-download even if cached')
|
|
81
|
+
.action(async (packageSpec, options) => {
|
|
82
|
+
await handleRun(packageSpec, options);
|
|
83
|
+
});
|
|
84
|
+
|
|
75
85
|
return program;
|
|
76
86
|
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { describe, it, expect, afterAll } from 'vitest';
|
|
2
|
+
import { RegistryClient } from '../../src/lib/api/registry-client.js';
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Integration tests for the mpak registry client
|
|
8
|
+
*
|
|
9
|
+
* These tests hit the live api.mpak.dev registry using the @nimblebraininc/echo
|
|
10
|
+
* bundle as a known fixture. They verify the full flow from search to download.
|
|
11
|
+
*
|
|
12
|
+
* Run with: npm run test:integration
|
|
13
|
+
*/
|
|
14
|
+
describe('RegistryClient Integration', () => {
|
|
15
|
+
const client = new RegistryClient();
|
|
16
|
+
const testBundle = '@nimblebraininc/echo';
|
|
17
|
+
const downloadedFiles: string[] = [];
|
|
18
|
+
|
|
19
|
+
afterAll(() => {
|
|
20
|
+
// Clean up any downloaded files
|
|
21
|
+
for (const file of downloadedFiles) {
|
|
22
|
+
if (fs.existsSync(file)) {
|
|
23
|
+
fs.unlinkSync(file);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe('searchBundles', () => {
|
|
29
|
+
it('should find echo bundle when searching for "echo"', async () => {
|
|
30
|
+
const result = await client.searchBundles('echo');
|
|
31
|
+
|
|
32
|
+
expect(result.bundles).toBeDefined();
|
|
33
|
+
expect(result.bundles.length).toBeGreaterThan(0);
|
|
34
|
+
|
|
35
|
+
const echoBundle = result.bundles.find(b => b.name === testBundle);
|
|
36
|
+
expect(echoBundle).toBeDefined();
|
|
37
|
+
expect(echoBundle?.description).toContain('Echo');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should return empty results for nonsense query', async () => {
|
|
41
|
+
const result = await client.searchBundles('xyznonexistent12345');
|
|
42
|
+
|
|
43
|
+
expect(result.bundles).toBeDefined();
|
|
44
|
+
expect(result.bundles.length).toBe(0);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should respect limit parameter', async () => {
|
|
48
|
+
const result = await client.searchBundles('', { limit: 1 });
|
|
49
|
+
|
|
50
|
+
expect(result.bundles.length).toBeLessThanOrEqual(1);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe('getBundle', () => {
|
|
55
|
+
it('should return bundle details for @nimblebraininc/echo', async () => {
|
|
56
|
+
const bundle = await client.getBundle(testBundle);
|
|
57
|
+
|
|
58
|
+
expect(bundle.name).toBe(testBundle);
|
|
59
|
+
expect(bundle.description).toBeDefined();
|
|
60
|
+
expect(bundle.server_type).toBe('python');
|
|
61
|
+
expect(bundle.author).toBeDefined();
|
|
62
|
+
expect(bundle.latest_version).toBeDefined();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('should include provenance information', async () => {
|
|
66
|
+
const bundle = await client.getBundle(testBundle);
|
|
67
|
+
|
|
68
|
+
expect(bundle.provenance).toBeDefined();
|
|
69
|
+
expect(bundle.provenance?.provider).toBe('github_oidc');
|
|
70
|
+
expect(bundle.provenance?.repository).toContain('mcp-echo');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should throw error for non-existent bundle', async () => {
|
|
74
|
+
await expect(
|
|
75
|
+
client.getBundle('@nonexistent/bundle-xyz')
|
|
76
|
+
).rejects.toThrow('Bundle not found');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should throw error for unscoped package name', async () => {
|
|
80
|
+
await expect(
|
|
81
|
+
client.getBundle('unscoped-name')
|
|
82
|
+
).rejects.toThrow('Package name must be scoped');
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
describe('getVersions', () => {
|
|
87
|
+
it('should return version list with platforms', async () => {
|
|
88
|
+
const result = await client.getVersions(testBundle);
|
|
89
|
+
|
|
90
|
+
expect(result.versions).toBeDefined();
|
|
91
|
+
expect(result.versions.length).toBeGreaterThan(0);
|
|
92
|
+
|
|
93
|
+
const latestVersion = result.versions[0];
|
|
94
|
+
expect(latestVersion.version).toBeDefined();
|
|
95
|
+
expect(latestVersion.platforms).toBeDefined();
|
|
96
|
+
expect(latestVersion.platforms.length).toBeGreaterThan(0);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should include linux platforms for echo bundle', async () => {
|
|
100
|
+
const result = await client.getVersions(testBundle);
|
|
101
|
+
|
|
102
|
+
const latestVersion = result.versions[0];
|
|
103
|
+
const platforms = latestVersion.platforms.map(p => `${p.os}-${p.arch}`);
|
|
104
|
+
|
|
105
|
+
expect(platforms).toContain('linux-x64');
|
|
106
|
+
expect(platforms).toContain('linux-arm64');
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
describe('getDownloadInfo', () => {
|
|
111
|
+
it('should return download URL for latest version', async () => {
|
|
112
|
+
const info = await client.getDownloadInfo(testBundle, undefined, {
|
|
113
|
+
os: 'linux',
|
|
114
|
+
arch: 'x64',
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
expect(info.url).toBeDefined();
|
|
118
|
+
expect(info.url).toMatch(/^https?:\/\//);
|
|
119
|
+
expect(info.bundle.version).toBeDefined();
|
|
120
|
+
expect(info.bundle.platform).toBeDefined();
|
|
121
|
+
expect(info.bundle.size).toBeGreaterThan(0);
|
|
122
|
+
expect(info.bundle.sha256).toBeDefined();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('should return correct artifact for requested platform', async () => {
|
|
126
|
+
const info = await client.getDownloadInfo(testBundle, undefined, {
|
|
127
|
+
os: 'linux',
|
|
128
|
+
arch: 'arm64',
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
expect(info.bundle.platform.os).toBe('linux');
|
|
132
|
+
expect(info.bundle.platform.arch).toBe('arm64');
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('should return download info for specific version', async () => {
|
|
136
|
+
const versions = await client.getVersions(testBundle);
|
|
137
|
+
const specificVersion = versions.versions[0].version;
|
|
138
|
+
|
|
139
|
+
const info = await client.getDownloadInfo(testBundle, specificVersion, {
|
|
140
|
+
os: 'linux',
|
|
141
|
+
arch: 'x64',
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
expect(info.bundle.version).toBe(specificVersion);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
describe('downloadBundle', () => {
|
|
149
|
+
it('should download bundle file successfully', async () => {
|
|
150
|
+
const info = await client.getDownloadInfo(testBundle, undefined, {
|
|
151
|
+
os: 'linux',
|
|
152
|
+
arch: 'x64',
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
const outputPath = path.join(
|
|
156
|
+
process.cwd(),
|
|
157
|
+
`test-download-${Date.now()}.mcpb`
|
|
158
|
+
);
|
|
159
|
+
downloadedFiles.push(outputPath);
|
|
160
|
+
|
|
161
|
+
await client.downloadBundle(info.url, outputPath);
|
|
162
|
+
|
|
163
|
+
expect(fs.existsSync(outputPath)).toBe(true);
|
|
164
|
+
|
|
165
|
+
const stats = fs.statSync(outputPath);
|
|
166
|
+
expect(stats.size).toBe(info.bundle.size);
|
|
167
|
+
}, 60000); // 60s timeout for download
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
describe('detectPlatform', () => {
|
|
171
|
+
it('should return valid platform object', () => {
|
|
172
|
+
const platform = RegistryClient.detectPlatform();
|
|
173
|
+
|
|
174
|
+
expect(platform.os).toBeDefined();
|
|
175
|
+
expect(platform.arch).toBeDefined();
|
|
176
|
+
expect(['darwin', 'linux', 'win32', 'any']).toContain(platform.os);
|
|
177
|
+
expect(['x64', 'arm64', 'any']).toContain(platform.arch);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
});
|
package/vitest.config.ts
CHANGED
|
@@ -4,10 +4,11 @@ export default defineConfig({
|
|
|
4
4
|
test: {
|
|
5
5
|
globals: true,
|
|
6
6
|
environment: 'node',
|
|
7
|
+
include: ['src/**/*.test.ts', 'test/**/*.test.ts'],
|
|
7
8
|
coverage: {
|
|
8
9
|
provider: 'v8',
|
|
9
10
|
reporter: ['text', 'json', 'html'],
|
|
10
|
-
exclude: ['dist', 'node_modules', '**/*.test.ts', '**/*.config.ts'],
|
|
11
|
+
exclude: ['dist', 'node_modules', '**/*.test.ts', '**/*.config.ts', 'test'],
|
|
11
12
|
},
|
|
12
13
|
},
|
|
13
14
|
});
|