@vocaless/mcp
Local MCP server for Vocaless. Lets an AI assistant strip vocals from audio
files on your own machine and transpose the instrumental, without you touching a
browser.
"Take the four tracks in ~/gigs/friday, strip the vocals, drop each one two
semitones, and give me the download links."
Why it runs locally
It runs on your machine, so it reads your audio files directly and uploads them
to storage itself using a presigned URL. A remote MCP server cannot do that:
there is no filesystem on the other end of a hosted chat client, which is why
this is a stdio server you install rather than a URL you point at.
Everything else goes through the same public API and the same credits as any
other client. No separate billing, no separate rate limits.
Setup
Create an API key under Developers → API keys in the dashboard, then add the
server to your MCP client.
Claude Code:
claude mcp add vocaless --env VOCALESS_API_KEY=vl_live_... -- npx -y @vocaless/mcp
Anything that reads a JSON config (Claude Desktop, Cursor, Windsurf):
{
"mcpServers": {
"vocaless": {
"command": "npx",
"args": ["-y", "@vocaless/mcp"],
"env": {
"VOCALESS_API_KEY": "vl_live_..."
}
}
}
}
VOCALESS_API_KEY | yes | — | From Developers → API keys. Revoke it there if it leaks. |
VOCALESS_BASE_URL | no | https://vocaless.app | Only set this to develop against a local server: http://localhost:3000 for just web. |
Tools
separate_vocals(file_path, duration_seconds?) | Reads the file, uploads it, charges credits, queues separation. Returns a song_id right away. |
get_stems(song_id, semitones?, speed?) | Download URLs for the result. Pass semitones (-6..6) or speed (50..200) for a transposed instrumental; it queues the render if it does not exist yet. |
check_balance() | Credit balance and storage usage. |
Notes worth knowing:
separate_vocals does not block. Separation takes minutes and MCP clients
time out tool calls in tens of seconds, so it returns a song_id and the
assistant polls get_stems.
- Pass
duration_seconds when you know it. Without it a flat fallback is
billed up front, then reconciled down once the worker reports the real length.
check_balance reports the live rates; this package deliberately hardcodes no
prices, since a published version can be months out of date.
- Transposing is free. Only separation costs credits, so iterating on key
and tempo costs nothing.
- Download URLs are presigned and expire in about an hour. Fetch them when
you need them rather than storing them.
- Unsupported file types are rejected before upload, so you are never
charged for a file the separator cannot read.
Development
pnpm install
pnpm typecheck
pnpm check
pnpm lint
pnpm build
There is no test runner and no tsx. Relative imports use the real .ts
extension so node src/anything.ts runs directly via type stripping, and tsc
rewrites those to .js on emit. Avoid TypeScript syntax that needs a real
transform (constructor parameter properties, enum, namespace) or plain node
stops being able to run the file.
pnpm check therefore needs a Node with unflagged type stripping: 22.18+ or
23.6+. The Nix dev shell's Node 22.20 qualifies. The published package is plain
JavaScript, so consumers only need the Node 20 in engines.
Run it against a local server end to end. VOCALESS_BASE_URL is required here,
since the default points at production:
VOCALESS_API_KEY=vl_live_... VOCALESS_BASE_URL=http://localhost:3000 node dist/index.js
That waits on stdin for JSON-RPC. To confirm the handshake and tool list without
an MCP client:
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"smoke","version":"0"}}}' \
'{"jsonrpc":"2.0","method":"notifications/initialized"}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
| VOCALESS_API_KEY=test node dist/index.js
stdout is the JSON-RPC channel. A stray console.log corrupts the protocol
stream and the client disconnects with a parse error. Diagnostics go to stderr.