Skip to main content
Glama
README.md
# WatermelonFin MCP

<img src="assets/logo.png" alt="WatermelonFin" width="96" />

A local Model Context Protocol (MCP) server for discovering Jellyfin servers, querying media libraries, importing **new** media, and repairing metadata/artwork of **your own completed video imports** through a companion Jellyfin plugin.

**Early preview.** The plugin targets Jellyfin 12.4.0. Uploads have been exercised on one actual server; the new v0.1.3 metadata repair path still requires deployment validation. Automated core, SDK adapter, HTTP, and MCP stdio tests do not establish loading/indexing compatibility on every host.

WatermelonFin MCP is an independent project maintained by [@MrWeiC](https://github.com/MrWeiC). It is not affiliated with or endorsed by Jellyfin or Tailscale. The WatermelonFin Apple clients are separate applications; this repository does not include automatic Apple client pairing or a drag-and-drop upload interface.

## Capabilities

- Discover Jellyfin on a user-specified host and a bounded set of ports.
- Authenticate with a restricted Jellyfin username/password or an existing user token; no prior browser login is required.
- List libraries and search media without modifying existing content.
- Inspect the local Tailscale CLI for candidate addresses and MagicDNS names.
- Expose an onboarding recipe as an MCP prompt/resource.
- Plan new imports and stream selected local files directly to the native upload plugin, with resumable chunks and SHA-256 verification.
- Inspect, repair, and restore metadata/artwork of your own completed video imports, with revision history and per-item refresh/readback.

There are **no media-deletion, video-overwrite, existing-media reorganization, arbitrary HTTP, arbitrary filesystem, or general shell tools**. Metadata repair can replace/restore bounded sidecars of owned imports; it cannot change video bytes or edit other media. The plugin starts disabled and requires an explicit user allowlist. These are application controls, not an operating-system sandbox; read [SECURITY.md](SECURITY.md).

## Requirements

| Component | Requirement |
| --- | --- |
| Local MCP | Node.js 22+ and a stdio-capable MCP host |
| Native plugin | Jellyfin 12.4.0; other server versions are unverified |
| Plugin development | .NET 10 SDK |
| Remote access | A trusted route to the server, such as your configured Tailscale network |

The native plugin reuses Jellyfin's port and user authentication. It does not require SSH, a separate upload port, a server-side Node installation, or the third-party RemoteUpload plugin. First-time plugin installation still requires a Jellyfin administrator and a server restart.

## Install the local MCP

Clone this repository, then run:

```sh
npm ci --ignore-scripts
npm test
```

Register the local entry point with your MCP host, replacing the absolute path:

```sh
codex mcp add watermelonfin -- node /absolute/path/watermelonfin-mcp/src/cli.js
```

For Claude Code:

```sh
claude mcp add watermelonfin -- node /absolute/path/watermelonfin-mcp/src/cli.js
```

A generic stdio configuration is available in [examples/mcp.json](examples/mcp.json). This preview is installed from source; no npm package is published. Host-specific registration commands may vary by host version.

An agent can retrieve the `onboard_jellyfin` prompt with a host address, or read `watermelonfin://recipes/onboard`. An IP address identifies a network destination; it does not grant login or administrator permissions.

## Credentials

Use a dedicated **non-administrator Jellyfin user with all media-deletion permissions disabled**. Administrator accounts, administrator API keys, and deletion-enabled users are rejected for daily operations.

Set `WATERMELONFIN_PROFILES` to non-secret connection metadata, for example:

```json
[{"id":"home","url":"https://media.example-tail.ts.net","serverId":"actual-server-id","username":"media-user","passwordEnv":"WATERMELONFIN_JELLYFIN_PASSWORD"}]
```

Supply the password in the referenced environment variable through your MCP host's secret configuration. **Do not paste passwords or tokens into chat, tool arguments, issues, or committed configuration files.** Call `authenticate_server` with only the profile ID. Session tokens obtained during login stay in process memory. Restarting the MCP requires a new login.

For an existing restricted-user token, use `tokenEnv` instead of `username` and `passwordEnv`. Environment variables are not a complete secret vault: the host agent and trusted processes under the same OS account remain part of the trust boundary. This preview does not provide its own secure-input UI, OS keychain adapter, or browser Quick Connect session import.

HTTPS uses normal certificate verification. HTTP credentials require prior establishment of a trusted LAN/Tailscale route and a host-configured, exact-origin allowlist in `WATERMELONFIN_TRUSTED_HTTP_ORIGINS`. Tools cannot modify this list. A matching Jellyfin server ID or a MagicDNS name is a consistency signal, not proof of server authenticity.

## Native upload plugin

The [v0.1.3 pre-release](https://github.com/MrWeiC/watermelonfin-mcp/releases/tag/v0.1.3) contains the compiled plugin ZIP and SHA-256 checksum. The official Jellyfin plugin repository URL is:

```text
https://raw.githubusercontent.com/MrWeiC/watermelonfin-mcp/main/catalog/manifest.json
```

See [the plugin guide](docs/plugin.md) for installation, configuration, endpoint details, and deployment limits.

Metadata repair requires the v0.1.3 MCP **and** native plugin. The published v0.1.2 package lacks it. See [owned-import metadata repair](docs/owned-import-metadata.md) for tools, revision/restore workflow, and upgrade verification. The official catalog includes v0.1.3.0 and the WatermelonFin logo.

1. Install the published plugin through Jellyfin's plugin repository/catalog and restart Jellyfin.
2. Keep uploads disabled until the administrator selects the intended import targets and allowlists a restricted user.
3. Add only the plugin's appropriate `Imported/<target-id>` directories as Jellyfin library sources. Preserve existing source paths; never index `Staging`.
4. Set `WATERMELONFIN_UPLOAD_ROOTS` to narrowly scoped local directories you explicitly permit the agent to upload from. Use `:` on Unix or `;` on Windows. The Unix uploader rejects symlinks and unsafe shared-write directory configurations.
5. Call `inspect_upload_plugin`, `list_upload_targets`, then `upload_media` with a selected file and target ID.

Bytes stream directly to the authenticated plugin, not through the model context. Each job is owned by one user. Publication uses a new job namespace and never replaces an existing destination. Ambiguous film/episode names require clarification; the `other` target type preserves a validated filename. Existing files are not automatically reorganized.

An interrupted upload can be resumed by supplying its job ID and the same file/target. Completed files cannot be modified through the upload API. **Upload completion does not mean Jellyfin has indexed the file.** Indexing relies on the configured library monitoring/schedule and must be verified separately. Expired/staged files are retained; there is no automatic cleanup route.

## Tools

| Tool | Purpose |
| --- | --- |
| `discover_server` | Bounded discovery on one specified host; no credentials |
| `inspect_connection` | Public server information at a full URL/base path |
| `inspect_tailscale` | Fixed, read-only local Tailscale status command |
| `inspect_capabilities` | Local configuration and implemented/unavailable capabilities |
| `authenticate_server` | Login through host-injected credentials |
| `list_libraries`, `search_media` | Restricted-user library reads |
| `plan_import` | A proposal for a new filename; no file changes |
| `inspect_upload_plugin`, `list_upload_targets` | Native plugin availability and configured targets |
| `upload_media` | Selected-file native plugin upload/resume |
| `inspect_import_metadata` | Fields, artwork, revision history, and verification of an owned completed video import |
| `update_import_metadata` | Revisioned metadata replacement and exact-item refresh/readback |
| `set_import_artwork` | Stream allowed local JPEG/PNG as primary/backdrop artwork for an owned import |
| `restore_import_metadata` | Restore that job's earlier metadata/artwork as a new revision |
| `refresh_import_metadata` | Reapply and refresh/read back the current owned-import revision |
| `export_connection` | Non-secret connection metadata; does not configure Apple clients |
| `upload_file` | Optional standalone-importer mode, only exposed when separately configured |

The legacy standalone importer is an optional alternative for operators who already have system-management access; it is **not required** by native plugin users. Its separate deployment contract is in [docs/provisioning.md](docs/provisioning.md).

## Local validation and release status

The v0.1.2 dependency refresh passed `npm audit --omit=dev` with zero known reported vulnerabilities on October 27, 2026. This is a point-in-time check, not a guarantee against undiscovered or future vulnerabilities. Use v0.1.2 or later rather than the initial v0.1.0 MCP dependency lockfile.

```sh
npm test
./scripts/validate-plugin.sh
```

The second command requires .NET 10 and builds/tests/packages the plugin locally. There are no GitHub Actions workflows. Tests include real MCP stdio initialization, simulated HTTP boundaries, temporary-filesystem uploads, and adapter checks against the actual Jellyfin SDK/JSON converters. They do not yet include loading this plugin in a complete Jellyfin instance or validating a production host's ACLs and indexing.

Pre-release plugin builds are intended for evaluation with a current backup and a small test import. Do not interpret this preview as a production-readiness or absolute no-data-loss guarantee.

## Maintenance and repository ownership

This is an owner-maintained repository. Only **@MrWeiC** is authorized to update the official branches/tags, merge changes, or publish official releases. Public visibility permits reading and forking; an external pull request is a proposal, not permission to change the official repository. Forks and independently built packages are not official releases.

See [CONTRIBUTING.md](CONTRIBUTING.md) for contribution expectations and [SECURITY.md](SECURITY.md) for vulnerability reporting. Licensing is described in [LICENSE.md](LICENSE.md).

TDQS

B3.4/5.0

Scored across 17 tools

Disambiguation4/5

Most tools have clearly distinct resource/action targets, especially upload, metadata revision, discovery, and connection inspection. The main possible confusion is among the several inspect_* tools and the metadata refresh/restore/inspect family, but their descriptions sufficiently distinguish ownership, scope, and side effects.

Naming Consistency5/5

All tools use snake_case and follow a predictable verb_noun pattern such as upload_media, list_libraries, inspect_connection, and restore_import_metadata. The convention is consistently applied throughout the set.

Tool Count4/5

Seventeen tools is slightly heavy but still reasonable for a server covering authentication, discovery, upload, metadata lifecycle, artwork, search, and connection inspection. Each tool appears to serve a distinct operational need rather than duplicating functionality.

Completeness4/5

The server covers the core lifecycle well: discovery, authentication, library/target listing, upload, metadata inspection/update/restore/refresh, artwork, search, and connection export/inspection. Deletion and broader media administration are absent, but that appears intentional given the safety-focused scope.

Maintenance

ActivityMaintained
ResponsivenessNo issues