sf-mm-mcp
This MCP server integrates with moviemagnet.site and showfeed.site to search for movies and TV shows, find torrents, and manage downloads via put.io — all through MCP clients like Claude Desktop.
🎬 Movie Discovery (no sign-in)
Search movies by title (
movies_search)Get full movie details by IMDb ID (
movies_get)Browse popular movies (
movies_popular)
📺 TV Show Discovery (no sign-in)
Search TV shows by title (
shows_search)Get show details and episodes, filterable by season (
shows_get)Browse popular shows (
shows_popular)
🧲 Torrent Finding (sign-in required)
Find movie torrents (magnet links) by IMDb ID, filterable by resolution and seeders (
movies_find_torrents)Find TV show torrents by IMDb ID, filterable by season, episode, resolution, and seeders (
shows_find_torrents)
⬇️ put.io Integration (sign-in required)
Download management: Add transfers (magnet/URL), list/cancel/clean transfers, check transfer progress
Account & files: View account info (username, disk space), browse files and folders
Favorites: Sync and manage a favorites list of IMDb IDs across the sites (
favorites_list,favorites_update)
🔐 Authentication
Initiate out-of-band device login (
putio_login), check status (putio_auth_status), and sign out (putio_logout)
⚙️ Additional Features
Caching to reduce load, rate‑limit handling, safe write retries
Configurable via environment variables (e.g., confirmation for transfers)
Supports stdio and HTTP transports
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@sf-mm-mcp Search for the movie Interstellar and find torrents"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
sf-mm-mcp
An MCP server that exposes moviemagnet.site (movies) and showfeed.site (TV shows) to LLM clients, with put.io as the download backend.
Search a title, find magnet links ranked by seeders, and start the download on put.io — all from inside Claude Desktop, Claude Code, opencode, or any other MCP client.
npx sf-mm-mcp login # one-time put.io sign-in
npx sf-mm-mcp # start the server on stdio
npx sf-mm-mcp http # ...or on streamable HTTP, for clients that connect by URLSetup
1. Add the server to your MCP client
The put.io app id (9525) is built in, so there is nothing to configure for a default
install.
Claude Desktop (claude_desktop_config.json), Claude Code (.mcp.json), and opencode
(opencode.json) all use the same shape:
{
"mcpServers": {
"sf-mm": {
"command": "npx",
"args": ["-y", "sf-mm-mcp"]
}
}
}opencode
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"sfmm": {
"type": "local",
"command": ["npx", "-y", "sf-mm-mcp"],
"enabled": true
}
}
}opencode prefixes tool names with the server name, so the tools appear as
sfmm_movies_search, sfmm_putio_login, and so on. Verify the connection with
opencode mcp list.
Note that opencode mcp auth does not apply here. That command drives OAuth for
remote MCP servers via dynamic client registration; this is a local stdio server that
manages its own put.io credential. Use the sign-in below instead.
See docs/clients.md for Cursor, VS Code, Windsurf, Zed,
Cline and others.
2. Sign in
Either run npx sf-mm-mcp login in a terminal, or ask your assistant to call the
putio_login tool and follow the instructions it returns.
putio_login is non-blocking by design, so the in-chat flow works: the tool returns a
code immediately, you enter it at put.io/link, and putio_auth_status confirms. The token
is stored per-machine, so signing in once covers every MCP client on that machine.
Related MCP server: Arr Suite MCP Server
Authentication
The default is put.io's OOB (out-of-band) device flow: the server requests a short code, you enter it at https://put.io/link, and the server polls until it is linked.
This is the default rather than the more familiar redirect flow for a specific reason: an npx-distributed package cannot hold a client secret. Anything baked into the tarball is readable by everyone who installs it. The OOB flow needs no secret and no loopback listener, so it also works over SSH and inside containers.
If you control the environment and prefer the redirect flow, set:
SF_MM_AUTH_FLOW=loopback
PUTIO_CLIENT_SECRET=... # supply it yourself; never commit it
PUTIO_REDIRECT_URI=http://127.0.0.1:41830/callbackThe redirect URI must match one registered on your put.io app. state is generated per
handshake and verified on the callback.
Where the token is stored
In order of preference:
PUTIO_TOKENenvironment variable, if set (nothing is persisted).OS keychain — macOS Keychain via
security, Linux viasecret-tool.A
0600file at~/.config/sf-mm-mcp/token.json.
npx sf-mm-mcp status reports which backend is in use. npx sf-mm-mcp logout clears it.
Tools
Discovery — no sign-in required
Tool | Purpose |
| Find movies by title, returns IMDb ids |
| Full details for one movie |
| Most-viewed movies on moviemagnet.site |
| Find TV shows by title |
| Show details plus episode list, optionally one season |
| Most-viewed shows on showfeed.site |
Torrents — sign-in required
Tool | Purpose |
| Magnets for a movie, filterable by resolution and seeders |
| Magnets for a show, filterable by season, episode, resolution |
Results are normalised to {title, magnet, sizeHuman, seeders, resolution, season, episode, ageDays}
and sorted by seeder count.
put.io — sign-in required
Tool | Purpose |
| Start a download from a magnet or URL |
| List transfers with progress |
| Poll a single transfer |
| Cancel or remove transfers |
| Clear completed transfer entries |
| Username and disk usage |
| Browse files and folders |
| Read and edit the favorites list |
Favorites are stored in the put.io account config under the same favorites key the two
websites use, so the list stays in sync across all three.
Auth
putio_login, putio_auth_status, putio_logout.
putio_login returns instructions immediately rather than blocking — waiting for a human
to finish a browser flow would hold the tool call open for minutes and most clients time
out first. Poll putio_auth_status to confirm.
Configuration
All optional.
Variable | Default | Purpose |
|
| put.io OAuth app id (public); override to use your own app |
| — | Use a token directly, skipping sign-in |
|
|
|
| — | Only for |
|
| Only for |
|
| Point at a dev instance |
|
| Point at a dev instance |
|
| |
|
| Require |
|
| Torrent result cache, seconds |
|
| Metadata cache, seconds |
|
|
|
|
|
|
|
|
|
|
| HTTP mode bind address |
|
| HTTP mode port |
|
| HTTP mode endpoint path |
| — | Require |
Transports
stdio (default) is what desktop MCP clients spawn. Streamable HTTP is for clients that connect by URL and cannot spawn a process — Open WebUI, for example:
SF_MM_HTTP_TOKEN=$(openssl rand -hex 32) npx -y sf-mm-mcp http
# → http://127.0.0.1:8009/mcpGET /health is available for supervisors and returns the running version.
HTTP mode shares one put.io account across every client that can reach the port. Unlike stdio, where the server belongs to a single desktop user, there is no per-user authorization: anyone who can call the endpoint can spend the linked account's storage and bandwidth. It therefore binds to loopback by default and refuses nothing else — bind wider only together with
SF_MM_HTTP_TOKEN, and considerSF_MM_CONFIRM_TRANSFERS=true.
See docs/clients.md for the Open WebUI setup and
a systemd unit.
Caching and rate limits
Both websites validate the put.io token on every /api/torrent request, and that endpoint
fans out to torrent indexers. An LLM will call these far more eagerly than a human
clicking through a web page, so this server:
caches torrent results (15 min) and metadata (1 hour) in process,
de-duplicates concurrent identical requests,
caches token-validation results for 10 minutes rather than revalidating per call,
honours put.io's
429plusX-RateLimit-Resetheaders with backoff,never retries a write, so a transfer cannot be silently created twice.
Development
npm install
npm run build
npm run typecheck
npm test # boots the server, asserts tool surface; no network
npm run smoke # exercises the live public endpoints over MCP stdionpm test is network-free on purpose, so CI does not go red because a torrent
indexer is having a bad day. It runs with SF_MM_TOKEN_STORE=none so it cannot
accidentally pick up a developer's real token and skip the auth-gating checks.
Releasing
npm version patch && git push --follow-tagsPublishing runs from GitHub Actions on a version tag. There is no npm token anywhere: the workflow authenticates with npm via OIDC trusted publishing, which also generates a provenance attestation automatically.
npm version patch # or minor / major - commits and tags
git push --follow-tags.github/workflows/publish.yml then refuses to continue unless:
the tag matches
package.jsonversion exactly,that version is not already on npm,
typecheck, build and the tool-surface test all pass,
no
.envfile made it into the tarball.
To rehearse without publishing, run the workflow manually from the Actions tab
with dry-run left checked. Full detail in
docs/releasing.md.
Documentation
Design decisions and why the alternatives lost | |
Credential model; why there is no client secret | |
The two sites' API surface and its quirks | |
Configuration for every common MCP client | |
Release procedure and CI guards |
Agents should start at AGENTS.md.
Point at local dev servers with MOVIEMAGNET_BASE_URL=http://localhost:5173.
Notes on the upstream APIs
Neither site publishes a schema, so the shapes in src/schemas.ts were derived by reading
the SvelteKit route handlers and probing the live endpoints. Two things worth knowing:
Both sites expect the put.io token in a bare
Authorizationheader with noBearerprefix. This client matches that.Neither site has a "create transfer" endpoint — the web apps do it client-side. So transfers, account info, and favorites go directly to
api.put.io.
Validation failures are logged rather than swallowed, so upstream schema drift shows up as a warning on stderr instead of a silent "no results found".
A bug this client used to work around
Both sites once returned 500 on the first request for any given title, because
torrentService.js destructured the Jackett response as const { instance, data: results }
— declaring a new block-scoped results that shadowed the outer one, leaving it undefined
on every cache miss. It hid well: the shadowed value was still written to Redis, so a retry
hit the cache and succeeded. Titles with zero indexer results were never cached and so
failed permanently.
Fixed and deployed in both apps (showfeed-app@6640310, moviemagnet-app@77b22fe),
along with queryMultipleServices, which only ever called resolve and therefore hung
forever if every indexer failed.
The 5xx retry in this client predates those fixes. It is kept because indexers still fail
transiently, but it is no longer masking a deterministic upstream failure. Full write-up in
docs/upstream-apis.md.
Credits
Logo icons from pepicons by CyCraft, licensed CC BY 4.0.
See assets/README.md.
Available Tools
20 toolsfavorites_listList favoritesARead-only
Lists the IMDb ids favorited in the put.io account config. This is the same list shown on showfeed.site and moviemagnet.site.
Inputs: no named parameters.
favorites_updateAdd or remove a favoriteAIdempotent
Adds or removes an IMDb id from the favorites list stored in the put.io account config.
Inputs: action (required), imdbId (required).
movies_find_torrentsFind movie torrentsARead-only
Searches torrent indexers for a movie by IMDb id and returns magnet links sorted by seeder count. Requires a put.io sign-in. Pass a magnet to putio_add_transfer to start downloading.
Inputs: imdbId (required), limit, minSeeders, resolutions, +1 more.
movies_getGet movie detailsARead-only
Fetches full details for a single movie by IMDb id from moviemagnet.site. No sign-in required.
Inputs: imdbId (required).
movies_popularList popular moviesARead-only
Returns the movies most viewed on moviemagnet.site recently. No sign-in required.
Inputs: no named parameters.
movies_searchSearch moviesARead-only
Searches moviemagnet.site for movies by title. Returns IMDb ids to pass to movies_get or movies_find_torrents. No sign-in required.
Inputs: query (required).
putio_accountGet put.io account infoARead-only
Returns the signed-in put.io username and remaining disk space.
Inputs: no named parameters.
putio_add_transferAdd a transfer to put.ioA
Starts a download on put.io from a magnet link or HTTP URL, typically one returned by movies_find_torrents or shows_find_torrents. This spends the account's bandwidth and storage, so confirm the choice with the user first.
Inputs: url (required), confirm, saveParentId.
putio_auth_statusCheck put.io sign-in statusARead-only
Reports whether a valid put.io token is stored, and the progress of any sign-in started by putio_login.
Inputs: no named parameters.
putio_cancel_transfersCancel put.io transfersADestructiveIdempotent
Cancels or removes transfers by id. Stops seeding if the transfer is seeding, otherwise removes the transfer entry. Downloaded files are not deleted.
Inputs: transferIds (required).
putio_clean_transfersClear completed put.io transfersADestructiveIdempotent
Removes all completed transfer entries from the transfer list. Downloaded files are not deleted.
Inputs: no named parameters.
putio_get_transferGet a put.io transferARead-only
Fetches up-to-date details for a single transfer, useful for checking download progress.
Inputs: transferId (required).
putio_list_filesList put.io filesARead-only
Lists files and folders in the put.io account. Pass a folder id to browse into it.
Inputs: parentId.
putio_list_transfersList put.io transfersARead-only
Lists current and recent transfers on the signed-in put.io account, with download progress.
Inputs: limit, status.
putio_loginSign in to put.ioA
Starts the put.io sign-in flow and returns instructions for the user to complete it in a browser. Call putio_auth_status afterwards to confirm completion. Required before searching torrents or creating transfers.
Inputs: force.
putio_logoutSign out of put.ioADestructive
Deletes the stored put.io token from the OS keychain or credential file.
Inputs: no named parameters.
shows_find_torrentsFind TV show torrentsARead-only
Searches torrent indexers for a show by IMDb id and returns magnet links sorted by seeder count. Filter to a specific season and episode to find a single airing. Requires a put.io sign-in.
Inputs: imdbId (required), limit, season, episode, +3 more.
shows_getGet TV show detailsARead-only
Fetches details for a single show by IMDb id, including its full episode list. No sign-in required.
Inputs: imdbId (required), season, includeEpisodes.
shows_popularList popular TV showsARead-only
Returns the shows most viewed on showfeed.site recently. No sign-in required.
Inputs: no named parameters.
shows_searchSearch TV showsARead-only
Searches showfeed.site for TV shows by title. Returns IMDb ids to pass to shows_get or shows_find_torrents. No sign-in required.
Inputs: query (required).
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 20 tools
Tools are cleanly namespaced by domain (movies_, shows_, putio_, favorites_) and each targets a distinct resource or action. The only potential source of confusion is putio_clean_transfers versus putio_cancel_transfers, but their descriptions clearly separate bulk cleanup of completed entries from targeted cancellation/removal.
Most tools follow a consistent [resource]_[action] pattern, with actions like get, search, add, list, cancel, update. A few outliers use adjectives or nouns for the suffix (movies_popular, putio_account, putio_auth_status), which breaks the verb_noun convention, but the overall prefix scheme remains predictable.
With 20 tools, the server is at the heavy end of the scale, but the count is justified by the multiple subdomains (movies, shows, put.io, favorites). It borders on feeling bloated, yet each tool serves a distinct function and the logical grouping helps manageability.
The tool surface covers the core lifecycle for discovering media, finding torrents, managing put.io transfers, and maintaining favorites. Notable minor gaps include no direct file deletion or transfer pause/resume, but these are workarounds.
Maintenance
Related MCP Connectors
Hosted MCP: download, transcribe, and get metadata for any video/audio URL. Managed yt-dlp.
1Automate 1,000+ services from any MCP-compatible AI agent: build Applets, run actions and queries.
MCP connector that lets ChatGPT list, search, and run your Apple Shortcuts via a local Mac agent
Publish and schedule videos to TikTok, YouTube Shorts, Instagram, Facebook, LinkedIn, Pinterest, Bluesky, Threads and X from Claude, Cursor or any MCP client. Upload once, post everywhere, track views in unified analytics, and retry failed posts. Official platform APIs only, free plan available. Docs: https://docs.multi-upload-tool.com/mcp
Related MCP Servers
AlicenseAqualityCmaintenanceGiving AI assistants the ability to search movies and TV shows, find torrents with magnet links, check streaming availability, and explore cast/crew metadata.661095 npm17MIT- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to manage media automation services like Sonarr, Radarr, Prowlarr, Bazarr, Overseerr, and Plex through natural language commands.8MIT
- AlicenseBqualityFmaintenanceEnables natural language interaction with MoviePilot media library automation, supporting search, discovery, subscription management, download control, and media status queries.109MIT
- AlicenseBqualityDmaintenanceEnables control and management of a self-hosted media stack (Radarr, Sonarr, Prowlarr, SABnzbd, qBittorrent) through natural language via MCP.15GPL 3.0