From Empty Repo to Self-Hosted v0.1: Run Your Own Sound Catalog MCP Server (5)
Four articles in, we've covered why an invisible catalog is a problem, why provenance belongs in the data model instead of a README, how search finds the right sound without a cloud API call, and why the whole thing is safe to hand an AI agent in the first place. None of that is worth much if you can't actually run it. So this last one is just that: clone it, get it talking to Claude Desktop, and, if you want it live, put it behind Docker.
What you're actually running
The project ships with a bundled demo catalog: 20 real audio files across 8 categories, covering all three license shapes the schema supports. It's not a placeholder fixture with three token entries. It's the same catalog the project's own automated tests run against.
One honest detail worth mentioning, because it's the kind of thing this series has tried to be upfront about throughout: every sound in that demo catalog is synthesized, not recorded. Sine and sawtooth oscillators, filtered white noise, simple envelopes, written by a small script committed right there in the repo. That wasn't a shortcut. Sourcing "real" CC0 audio from someone else without being able to verify its actual license status on the spot would be exactly the kind of provenance problem this whole project exists to solve, so the demo catalog sidesteps that by being the sole rights holder of every file in it, with a creation story you can read in the same commit.
Running it locally
You need Node 20 or newer and pnpm. From there:
1. Clone and install
git clone https://github.com/insectaudio/sound-catalog-mcp.git
cd sound-catalog-mcp
pnpm install && pnpm build2. Index the demo catalog
pnpm ingest --catalog examples/demo-catalogThis reads every sound's manifest, computes its embeddings, and writes a SQLite index next to the catalog. Re-run it any time the catalog changes; the server never writes to this file itself, only ever reads it.
3. Run the server by hand, once, to confirm it starts cleanly
PREVIEW_SIGNING_SECRET="$(openssl rand -base64 32)" \
CATALOG_DIR=examples/demo-catalog \
node packages/server/dist/stdio.jsA clean start prints nothing to stdout, that's reserved entirely for the protocol itself, and one structured log line to stderr confirming it connected. Stop it with Ctrl-C.
4. Connect Claude Desktop
Add an entry to claude_desktop_config.json (on macOS, ~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"sound-catalog": {
"command": "node",
"args": ["/absolute/path/to/sound-catalog-mcp/packages/server/dist/stdio.js"],
"env": {
"CATALOG_DIR": "/absolute/path/to/sound-catalog-mcp/examples/demo-catalog",
"PREVIEW_SIGNING_SECRET": "<the same secret from step 3>"
}
}
}
}Restart Claude Desktop, and it should show sound-catalog connected with five tools available. Ask it something like "what's in the sound-catalog MCP server, and can you find me a metallic-sounding sample?" and watch it walk through list_catalog_info, then search_sounds, then describe_sound, pulling in get_license or get_preview if you push further.
Pointing it at your own catalog
Everything above works exactly the same way against a catalog you write yourself; just point --catalog at your own directory instead of examples/demo-catalog. Writing a catalog.json by hand that actually validates against the schema is its own small topic, covered in the project's authoring guide rather than repeated here.
Running it for real
The local walkthrough above is stdio only, meant for one client on one machine. A shared or production deployment uses the hosted HTTP transport instead, and the project ships a docker-compose.yml for exactly that.
cp .env.example .env# set PREVIEW_SIGNING_SECRET and MCP_AUTH_TOKEN in .env, each via
# openssl rand -base64 32
docker compose build
docker compose --profile ingest run --rm ingest
docker compose up -d
curl http://localhost:3000/healthz
The ingest step runs as a Compose profile, so it never starts as part of a normal docker compose up, only when you explicitly invoke it, and it writes into a named volume rather than the catalog directory itself, which gets mounted read-only. That's the same read-only guarantee from the previous article, now enforced at the filesystem level, not just in the application code.
From there, the deployment story is boring in the way you actually want infrastructure to be boring: put the container behind something like Coolify's built-in Traefik for TLS, wire its healthcheck to /healthz, and rotating either secret is a restart, not a rebuild.
What v0.1 deliberately doesn't do yet
No multi-tenancy. No auth beyond a single static token per deployment. No audio-similarity search by acoustic features, only by the text description right now. None of that is an oversight; it's a scope line drawn on purpose, documented in the project's own roadmap rather than left implicit. Multi-tenancy and proper per-client auth are planned for a later version, once the single-tenant read-only story has actually been proven out by people using it.
That's the series
Clone it. Point it at your own catalog, or just poke at the demo one for an afternoon. And if something breaks, or works in a way that surprises you, that's genuinely useful to hear about: the project is open source at github.com/insectaudio/sound-catalog-mcp.