slskd MCP
by jgalluzzi
README.md
# slskd MCP
A small, dependency-light [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server for controlling an existing [slskd](https://github.com/slskd/slskd) instance.
It gives an MCP-compatible agent three tools:
- `search_music` — run a Soulseek search and return peer/file metadata.
- `queue_download` — queue one exact result after an explicit rights confirmation.
- `list_downloads` — inspect current and completed transfers.
This project does not implement the Soulseek protocol. It communicates with the HTTP API exposed by your own slskd server.
> [!IMPORTANT]
> Use this software only to obtain files you own, public-domain or freely licensed material, or files you otherwise have permission to download. You are responsible for complying with copyright law and the rules that apply where you live.
## Requirements
- A working slskd instance connected to the Soulseek network.
- A slskd API key with the `readwrite` role.
- Node.js 18 or newer, or PowerShell 7 or newer.
- An MCP-compatible client such as Codex.
## Repository contents
| File | Purpose |
| --- | --- |
| `server.mjs` | Portable Node.js MCP server. |
| `server.ps1` | Dependency-free PowerShell MCP server. |
| `package.json` | Node.js scripts and package metadata. |
| `queue_existing_flac.ps1` | Experimental helper that evaluates stored searches. |
| `queue_new_flac.ps1` | Experimental helper for throttled searches and FLAC selection. |
| `bulk_flac.ps1` | Early bulk-search prototype; use conservative settings. |
The batch helpers are operational examples, not generic MCP tools. Review their matching rules, limits, and local state before using them with your own tracklist.
## 1. Configure slskd
Add a dedicated API key to `slskd.yml`. API keys must be between 16 and 255 characters.
```yaml
web:
port: 5030
ip_address: "0.0.0.0"
authentication:
disabled: false
username: "change-this-dashboard-username"
password: "change-this-dashboard-password"
api_keys:
mcp:
key: "replace-with-a-long-random-secret"
role: readwrite
cidr: "127.0.0.1/32,::1/128"
```
Generate a 32-byte secret with PowerShell:
```powershell
[Convert]::ToHexString(
[Security.Cryptography.RandomNumberGenerator]::GetBytes(32)
)
```
Restart slskd after changing its configuration.
### CIDR considerations
The loopback-only CIDR above is appropriate when the MCP server runs on the same host as slskd or connects through an SSH tunnel.
With Docker, requests forwarded from the host may appear to originate from the Docker bridge gateway, such as `172.17.0.1`. Obtain the actual gateway with:
```bash
docker inspect slskd --format '{{range .NetworkSettings.Networks}}{{.Gateway}}{{end}}'
```
If required, add that exact address as a `/32` entry. Avoid unrestricted API keys, especially when slskd is exposed over plain HTTP.
## 2. Set environment variables
| Variable | Required | Default | Description |
| --- | --- | --- | --- |
| `SLSKD_API_KEY` | Yes | — | Dedicated slskd `readwrite` API key. |
| `SLSKD_URL` | No | `http://localhost:5030` | Base URL of the slskd web/API service. |
PowerShell:
```powershell
$env:SLSKD_URL = "http://localhost:5030"
$env:SLSKD_API_KEY = "your-api-key"
```
POSIX shell:
```bash
export SLSKD_URL="http://localhost:5030"
export SLSKD_API_KEY="your-api-key"
```
Do not commit API keys, passwords, `.env` files, or populated slskd configuration files.
## 3. Configure the MCP client
Clone this repository and use an absolute path in your MCP configuration.
### Node.js
```toml
[mcp_servers.slskd]
command = "node"
args = ["/absolute/path/to/slskd-mcp/server.mjs"]
env_vars = ["SLSKD_URL", "SLSKD_API_KEY"]
```
Windows example:
```toml
[mcp_servers.slskd]
command = "node"
args = ["C:\\path\\to\\slskd-mcp\\server.mjs"]
env_vars = ["SLSKD_URL", "SLSKD_API_KEY"]
```
### PowerShell 7
```toml
[mcp_servers.slskd]
command = "pwsh"
args = ["-NoProfile", "-File", "/absolute/path/to/slskd-mcp/server.ps1"]
env_vars = ["SLSKD_URL", "SLSKD_API_KEY"]
```
Restart the MCP client after changing its configuration or persistent environment variables.
## Remote slskd over SSH
For a slskd instance on another machine, an SSH tunnel keeps the API off the public internet:
```powershell
ssh `
-N `
-o ServerAliveInterval=20 `
-o ServerAliveCountMax=3 `
-o TCPKeepAlive=yes `
-o Compression=no `
-o MACs=hmac-sha2-256-etm@openssh.com `
-L 5030:127.0.0.1:5030 `
root@208.68.38.142
```
Run this in a dedicated PowerShell window and keep it open. No output after
login is normal: `-N` tells SSH to create the tunnel without opening a remote
shell. Configure `SLSKD_URL=http://localhost:5030`.
If the host address or SSH account changes, replace `root@208.68.38.142`.
## Usage
Example agent prompts:
```text
Search Soulseek for an authorized Creative Commons release by Artist Name.
Do not download anything yet.
```
```text
Show the best unlocked FLAC matches with free upload slots and short queues.
```
```text
I confirm I own this release. Queue the exact selected result.
```
Search and download are intentionally separate. `queue_download` requires `rights_confirmed: true`.
## Search and load guidance
Soulseek searches are live network operations, not catalog lookups. Results vary with peer availability and may take several seconds.
For small servers, particularly instances with around 1 GB of memory:
- Keep concurrent searches low.
- Process one batch completely before starting another.
- Start with batches of 5–10 searches.
- Avoid printing entire raw response collections through the MCP client.
- Prefer compact result limits and exact local filtering.
- Reuse completed searches instead of immediately repeating them.
A green/completed search in the slskd dashboard means the search ended; it does not mean a file was downloaded.
## Development
No third-party Node packages are required.
```bash
npm run check
npm start
```
The server communicates over newline-delimited JSON-RPC on standard input/output. Application logs and diagnostic text must not be written to standard output because that would corrupt the MCP transport.
## Troubleshooting
### `401 Unauthorized`
- Confirm `SLSKD_API_KEY` contains the current key.
- Confirm the key has the `readwrite` role.
- Verify its CIDR includes the address slskd sees, including a Docker bridge gateway when applicable.
- Restart the MCP client after changing persistent environment variables.
### `Connection refused` on `localhost:5030`
- Confirm slskd is running and listening on port 5030.
- If using SSH, confirm the tunnel process is still running.
- Check `docker ps`, `docker logs slskd`, and `ss -lntp | grep ':5030'` on the server.
First check slskd locally on the VPS:
```bash
docker ps --filter name=slskd
curl -I --max-time 10 http://127.0.0.1:5030
docker logs --tail 30 slskd
```
Then, from Windows, verify the forwarded endpoint:
```powershell
Invoke-WebRequest http://localhost:5030 -UseBasicParsing
```
If the VPS check succeeds but the Windows check fails, stop the old tunnel
with `Ctrl+C` in its PowerShell window and start it again using the command in
the **Remote slskd over SSH** section. Do not start new search batches until
the tunnel works and slskd reports `Connected, LoggedIn`.
### SSH tunnel reports `message authentication code incorrect`
This means the SSH connection was corrupted or interrupted; it is not an
slskd API authentication error. Close the failed SSH session and reconnect.
The tunnel command above disables compression, selects a modern encrypt-then-MAC
algorithm, and enables keepalives to detect broken connections promptly.
If it continues:
- Check the VPS console for network pressure, reboots, or SSH daemon errors.
- Try the connection from a different network to rule out a faulty middlebox.
- Update the OpenSSH client and server.
- Run `ssh -vvv root@208.68.38.142` for diagnostic output, taking care not to
share private keys, credentials, or other sensitive output.
### `address already in use` for `[::]:5030`
Some Linux environments treat an IPv6 listener as dual-stack, causing it to conflict with an IPv4 listener. Configure only one address:
```yaml
web:
port: 5030
ip_address: "0.0.0.0"
```
### Downloads fail while searches still appear
Check `GET /api/v0/server` or the slskd dashboard. slskd must report `Connected, LoggedIn` before it can resolve a peer and enqueue a download. `Connected, LoggingIn` is not sufficient.
### slskd repeatedly disconnects or times out
- Stop submitting new searches.
- Allow queued searches to complete or cancel them.
- Wait for slskd to reconnect and reach `Connected, LoggedIn`.
- Resume with a smaller batch size.
## Security notes
- Treat the API key like a password.
- Prefer loopback access plus SSH tunneling for remote instances.
- Do not expose port 5030 publicly without HTTPS, authentication, firewalling, and a carefully restricted CIDR.
- Use a dedicated API key rather than reusing dashboard or Soulseek credentials.
- Keep Soulseek credentials in slskd; this MCP server does not need them.
## License
This project is dedicated to the public domain under
[CC0 1.0 Universal](LICENSE). You may copy, modify, distribute, and use it
for any purpose, including commercially, without asking permission.
CC0 applies only to material owned by this project's contributors. slskd,
Soulseek, and other third-party software or content retain their respective
licenses and rights.
TDQS
A3.8/5.0
Scored across 3 tools
Disambiguation5/5
Each tool has a clear, non-overlapping purpose: searching, queueing a specific result, and listing downloads. An agent would not struggle to select the correct tool for a given step.
Naming Consistency5/5
All tool names follow a consistent verb_noun pattern: search_music, queue_download, list_downloads. The naming is predictable and immediately conveys the action and target.
Tool Count5/5
Three tools is a tight, well-scoped set for the core search-and-download workflow. Each tool earns its place without unnecessary bulk or overlap.
Completeness4/5
The surface covers the primary workflow of searching, queueing downloads, and checking progress. Missing management actions like canceling, pausing, or retrying downloads are minor gaps for the stated scope.
Maintenance
ActivityMaintained
ResponsivenessNo issues