Cloud object storage for media creators, from your terminal.
Upload, organize, search, and share media on MediaLocker — presigned uploads/downloads, buckets, tags, categories, sets, storyboards, usage, and API keys. Plus a built-in MCP server so AI agents can drive your library.
npm install -g medialocker
# or run without installing
npx medialocker --helpRequires Node.js ≥ 22.
# 1. Point at your MediaLocker (defaults to https://api.medialocker.io)
medialocker config set url https://api.medialocker.io
# 2. Authenticate with an API key secret (mint one in the dashboard → API Keys,
# or with `medialocker apikeys create`). Verifies against /me and saves it.
medialocker login
# 3. Use it
medialocker buckets list
medialocker media upload ./hero.mp4 --bucket marketing --tag launch
medialocker media list --bucket marketing --kind video
medialocker search "drone shot" --kind videoUploads and downloads stream directly to/from object storage over presigned URLs — the API never touches your bytes. Large files automatically switch to multipart.
Every setting resolves with this precedence (highest wins):
- Flags —
--url,--api-key(work in any position) - Environment —
MEDIALOCKER_API_URL,MEDIALOCKER_API_KEY - Profile — the active profile in
~/.config/medialocker/config.json - Default —
https://api.medialocker.io
Authentication uses an API-key secret sent as Authorization: Bearer <secret>. The config file is written with 0600 permissions. Use --profile <name> (or config set default-profile <name>) to switch between, say, production and a self-hosted instance:
medialocker --profile local --url http://localhost:3002 login
medialocker --profile local buckets listInspect what's in effect:
medialocker config list| Group | Highlights |
|---|---|
login / logout / whoami |
Store/clear an API key; show the principal behind it |
config |
set / get / list — URL, API key, default profile |
buckets |
list, create, info, rm |
media |
list, upload, download, info, rm, metadata, url, thumbnail |
search |
full-text + facet search across media |
tags |
list, create, rm, set <objectId> --tags … |
categories |
list (tree), create [--parent], rm, set … |
sets |
list, create, info, add-item, rm-item, generate, rm |
storyboards |
list, create, info, add-clip, reorder, update-clip, rm-clip, rm |
usage |
show, history, events |
billing |
subscription, portal, invoices, plans |
apikeys |
list, create, revoke, rotate |
mcp |
serve (stdio MCP server), install (client config) |
Run medialocker <group> --help for the full option list of any command.
Add --json to any command for clean, pipeable output (banner, spinners, and notes go to stderr, so stdout stays pure):
medialocker --json media list --bucket marketing | jq -r '.items[].key'
medialocker --json buckets list | jq '.[].name'Exit codes are script-friendly: 0 ok, 2 usage, 3 auth, 4 network, 5 not-found, 1 generic.
The CLI doubles as a Model Context Protocol server, exposing your library to AI agents (Claude Desktop, Cursor, …):
# Print a config block (or --write to merge into Claude Desktop)
medialocker mcp install --client claude
medialocker mcp install --client claude --writeThis wires up a medialocker MCP server that runs medialocker mcp serve with tools for list_buckets, create_bucket, list_media, search_media, get_object, get_object_url, upload_object, and get_usage — all scoped to the API key in your config.
pnpm install
pnpm dev # tsup --watch
pnpm test # node:test via tsx
pnpm lint
pnpm typecheck
pnpm build # bundle to dist/index.js
node bin/medialocker.js --helpSee CONTRIBUTING.md.
AGPL-3.0-only © MediaLocker. If you run a modified version as a network service, you must offer your users its source.