@nimblebrain/mpak-sdk

TypeScript SDK for the mpak registry — search, download, cache, configure, and run MCPB bundles and Agent Skills.
Installation
pnpm add @nimblebrain/mpak-sdk
Quick Start
The MpakSDK facade is the primary entry point. It wires together the registry client, local cache, and config manager:
import { MpakSDK } from '@nimblebrain/mpak-sdk';
const mpak = new MpakSDK();
const server = await mpak.prepareServer('@nimblebraininc/echo');
import { spawn } from 'child_process';
const child = spawn(server.command, server.args, {
env: { ...server.env, ...process.env },
cwd: server.cwd,
stdio: 'inherit',
});
Usage
Prepare and Run a Server
prepareServer handles the full lifecycle: download, cache, read manifest, validate config, and resolve the command:
const mpak = new MpakSDK();
const server = await mpak.prepareServer('@scope/bundle');
const server = await mpak.prepareServer('@scope/bundle@1.2.0');
const server = await mpak.prepareServer('@scope/bundle', {
version: '1.2.0',
force: true,
});
const server = await mpak.prepareServer('@scope/bundle', {
workspaceDir: '/path/to/project/.mpak',
});
const server = await mpak.prepareServer('@scope/bundle', {
env: { DEBUG: 'true' },
});
The returned ServerCommand contains everything needed to spawn:
server.command;
server.args;
server.env;
server.cwd;
server.name;
server.version;
User Config (per-package settings)
Bundles can declare required configuration (API keys, ports, etc.) in their manifest. Store values before running:
const mpak = new MpakSDK();
mpak.config.setPackageConfigValue('@scope/bundle', 'api_key', 'sk-...');
Parse Package Specs
Validate and parse @scope/name or @scope/name@version strings:
MpakSDK.parsePackageSpec('@scope/name');
MpakSDK.parsePackageSpec('@scope/name@1.0.0');
MpakSDK.parsePackageSpec('invalid');
Search Bundles
const mpak = new MpakSDK();
const results = await mpak.client.searchBundles({ q: 'mcp', limit: 10 });
for (const bundle of results.bundles) {
console.log(`${bundle.name}@${bundle.latest_version}`);
}
Get Bundle Details
const bundle = await mpak.client.getBundle('@nimblebraininc/echo');
console.log(bundle.description);
console.log(`Versions: ${bundle.versions.map(v => v.version).join(', ')}`);
Platform-Specific Downloads
const platform = MpakClient.detectPlatform();
const download = await mpak.client.getBundleDownload(
'@nimblebraininc/echo',
'0.1.3',
platform
);
Cache Operations
const mpak = new MpakSDK();
const result = await mpak.cache.loadBundle('@scope/name');
console.log(result.cacheDir);
console.log(result.version);
console.log(result.pulled);
const manifest = mpak.cache.readManifest('@scope/name');
const bundles = mpak.cache.listCachedBundles();
await mpak.cache.checkForUpdateAsync('@scope/name');
const meta = mpak.cache.getCacheMetadata('@scope/name');
Config Manager
const mpak = new MpakSDK();
mpak.config.getRegistryUrl();
mpak.config.setRegistryUrl('https://custom.registry.dev');
mpak.config.setPackageConfigValue('@scope/name', 'api_key', 'sk-...');
mpak.config.getPackageConfigValue('@scope/name', 'api_key');
mpak.config.getPackageConfig('@scope/name');
mpak.config.clearPackageConfig('@scope/name');
mpak.config.clearPackageConfigValue('@scope/name', 'api_key');
mpak.config.listPackagesWithConfig();
Search & Download Skills
const mpak = new MpakSDK();
const skills = await mpak.client.searchSkills({ q: 'crm', limit: 10 });
for (const skill of skills.skills) {
console.log(`${skill.name}: ${skill.description}`);
}
const download = await mpak.client.getSkillDownload('@nimbletools/folk-crm');
const data = await mpak.client.downloadContent(download.url, download.skill.sha256);
Constructor Options
const mpak = new MpakSDK({
mpakHome: '~/.mpak',
registryUrl: 'https://registry.mpak.dev',
timeout: 30000,
userAgent: 'my-app/1.0',
logger: (msg) => console.error(msg),
});
Error Handling
import {
MpakSDK,
MpakNotFoundError,
MpakIntegrityError,
MpakNetworkError,
} from '@nimblebrain/mpak-sdk';
try {
const server = await mpak.prepareServer('@nonexistent/bundle');
} catch (error) {
if (error instanceof MpakNotFoundError) {
console.error('Bundle not found:', error.message);
} else if (error instanceof MpakIntegrityError) {
console.error('Expected SHA256:', error.expected);
console.error('Actual SHA256:', error.actual);
} else if (error instanceof MpakNetworkError) {
console.error('Network error:', error.message);
}
}
API Reference
MpakSDK (facade)
prepareServer(packageName, options?) | Resolve a bundle into a ready-to-spawn ServerCommand |
MpakSDK.parsePackageSpec(spec) | Parse and validate a @scope/name[@version] string |
Properties: config (ConfigManager), client (MpakClient), cache (BundleCache).
MpakClient (mpak.client)
Bundle Methods
searchBundles(params?) | Search for bundles |
getBundle(name) | Get bundle details |
getBundleVersions(name) | List all versions |
getBundleVersion(name, version) | Get specific version info |
getBundleDownload(name, version, platform?) | Get download URL and metadata |
downloadBundle(name, version?) | Download bundle with integrity verification |
downloadContent(url, sha256) | Download any content with SHA256 verification |
Skill Methods
searchSkills(params?) | Search for skills |
getSkill(name) | Get skill details |
getSkillDownload(name) | Get latest version download info |
getSkillVersionDownload(name, version) | Get specific version download info |
downloadSkillBundle(name, version?) | Download skill bundle with integrity verification |
Static Methods
MpakClient.detectPlatform() | Detect current OS and architecture |
BundleCache (mpak.cache)
loadBundle(name, options?) | Download and cache a bundle (skips if cached) |
readManifest(packageName) | Read and validate a cached bundle's manifest.json |
getCacheMetadata(packageName) | Read cache metadata for a package |
writeCacheMetadata(packageName, metadata) | Write cache metadata |
listCachedBundles() | List all cached registry bundles |
getPackageCachePath(packageName) | Get the cache directory path for a package |
checkForUpdateAsync(packageName) | Fire-and-forget update check (logs result) |
Utility Exports
Standalone functions exported from the package (not methods on any class):
extractZip(zipPath, destDir, options?) | Async. Stream-extract a ZIP with zip-bomb, path-traversal, and symlink protection. Pass { maxUncompressedSize } to override the default cap. |
MAX_UNCOMPRESSED_SIZE | Default uncompressed-size cap applied by extractZip (2 GB). |
isSemverEqual(a, b) | Compare semver strings (ignores v prefix) |
validateMcpb(path) | Async. Validate a local .mcpb file (manifest schema + entry-point existence) without touching the cache. Returns { valid: true, manifest } or { valid: false, errors }. |
ConfigManager (mpak.config)
getRegistryUrl() | Get the registry URL (respects MPAK_REGISTRY_URL env var) |
setRegistryUrl(url) | Override the registry URL |
getPackageConfig(packageName) | Get all stored config for a package |
getPackageConfigValue(packageName, key) | Get a single config value |
setPackageConfigValue(packageName, key, value) | Store a config value |
clearPackageConfig(packageName) | Remove all config for a package |
clearPackageConfigValue(packageName, key) | Remove a single config key |
listPackagesWithConfig() | List packages that have stored config |
Property: mpakHome (readonly) — the root directory for mpak state.
Error Types
MpakError | Base error class |
MpakNotFoundError | Resource not found (404) |
MpakIntegrityError | SHA256 hash mismatch (content NOT returned) |
MpakNetworkError | Network failures, timeouts |
Types
MpakSDKOptions | Constructor options for MpakSDK |
MpakClientConfig | Constructor options for MpakClient |
PrepareServerOptions | Options for prepareServer |
ServerCommand | Return type of prepareServer |
McpbManifest | Parsed MCPB manifest schema |
UserConfigField | User config field definition from manifest |
Development
pnpm install
pnpm test
pnpm test:integration
pnpm typecheck
pnpm build
Verification
Run all checks before submitting changes:
pnpm --filter @nimblebrain/mpak-sdk lint
pnpm --filter @nimblebrain/mpak-sdk typecheck
pnpm --filter @nimblebrain/mpak-sdk test
pnpm --filter @nimblebrain/mpak-sdk test:integration
Releasing
Releases are automated via GitHub Actions. The publish workflow is triggered by git tags.
Version is defined in one place: package.json.
Steps
-
Bump version in package.json:
cd packages/sdk-typescript
npm version patch
npm version minor
npm version major
-
Commit and push:
git commit -am "sdk-typescript: bump to X.Y.Z"
git push
-
Tag and push (this triggers the publish):
git tag sdk-typescript-vX.Y.Z
git push origin sdk-typescript-vX.Y.Z
CI will run the full verification suite, verify the tag matches package.json, build, and publish to npm. See sdk-typescript-publish.yml.
License
Apache-2.0