streamystats-mcp-server
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., "@streamystats-mcp-serverCheck the health of my Streamystats instance."
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.
streamystats-mcp-server
A minimal Model Context Protocol server that connects to Streamystats (a self-hosted watch-statistics dashboard for Jellyfin), packaged for Docker.
It runs as a standing network service (streamable-http transport, not stdio),
so any MCP client on your internal network can connect to
http://<host>:<port>/mcp — the container isn't spawned per-client, and
container lifecycle/updates can be handed off to a tool like
Dockhand.
Read this before trusting it for "watch stats"
Streamystats has no documented public REST API. Its dashboard, watch-time,
most-watched, and per-user history pages are server-rendered React components
that query its Postgres database directly — they are not exposed as JSON
endpoints any external client (including this one) can call. This was
confirmed by reading its main branch source directly (commit 1a154af6e59b,
2026-09-13), not by guessing from the README, which doesn't document an API
at all.
Only six app/api/**/route.ts handlers exist in the whole codebase, and of
those, only three groups accept external-client authentication
(requireAuth/no-auth-at-all in lib/api-auth.ts) rather than requiring a
logged-in browser session cookie (requireSession/requireAdmin, which this
server cannot obtain and does not attempt to):
Endpoint | Auth | Usable from here? |
| none | yes — |
| none | yes — |
| none | yes — |
| external-client OK | yes — |
| external-client OK | yes — |
| external-client OK | yes — |
everything else (dashboard stats, history, sessions, libraries, ...) | session cookie only | no |
That means this server cannot answer "what's my most-watched show" or "how much has user X watched" — despite that being Streamystats' whole purpose — because there is no API for it to call. If Streamystats adds a documented stats API in the future, this server should be extended to use it; until then, use the Streamystats web dashboard directly for that data.
Treat everything here as best-effort against an undocumented, unofficial
surface that a Streamystats upgrade could change or remove with no notice.
tests/test_live_streamystats.py exists specifically to catch that kind of
drift against a real instance — see Testing.
Related MCP server: Jellyseerr MCP Server
Tools
Tool | Description |
| List the Jellyfin servers Streamystats is tracking, with sync status |
| Search Streamystats' indexed library items, users, watchlists, activity, sessions, and people |
| List watchlists visible to the authenticated Jellyfin identity |
| Create a new watchlist |
| Streamystats liveness and version/update-check info |
create_watchlist is the only tool that changes state. Everything else is
read-only.
Authentication to Streamystats
Streamystats has no API key of its own for external clients. Per its
lib/api-auth.ts, it instead accepts a real Jellyfin API key or user access
token, sent as Authorization: MediaBrowser Token="<token>", and validates
that token directly against the Jellyfin server(s) it has registered. Set
STREAMYSTATS_JELLYFIN_TOKEN to a Jellyfin API key (Jellyfin > Dashboard >
API Keys) — not anything issued by Streamystats itself, because it issues
nothing.
Health endpoints
Two plain HTTP endpoints, reachable without MCP_AUTH_TOKEN (so Docker's
HEALTHCHECK, Dockhand, or any other monitor can poll them without the
secret):
Endpoint | Checks | Healthy | Unhealthy |
| The process is up and serving HTTP. Does not call Streamystats. |
| (doesn't respond) |
|
|
|
|
Configuration
Environment variables (see .env.example):
Variable | Required | Default | Description |
| yes | — | e.g. |
| yes | — | A Jellyfin API key/token — see Authentication |
| no |
| Interface the server binds to inside the container |
| no |
| Port the server listens on |
| no | — | Shared secret required as |
Image
Built and pushed to ghcr.io/barrow1990/streamystats-mcp-server by
.github/workflows/ci.yml on every push to
main that passes tests, tagged :latest and :<commit-sha>.
docker-compose.yml pulls :latest by default; swap in build: . there
instead if you'd rather build locally from the Dockerfile.
Same three-stage scratch-flattened Alpine build as the sonarr/radarr MCP servers (~98MB) — see those repos' READMEs for why that design shrinks the image the way it does.
Running with Docker Compose
cp .env.example .env # fill in STREAMYSTATS_URL / STREAMYSTATS_JELLYFIN_TOKEN
docker compose up -d --pull alwaysThe server is then reachable at http://<docker-host>:8940/mcp from anything
on your internal network.
Managing with Dockhand
Point Dockhand at ghcr.io/barrow1990/streamystats-mcp-server and let it
track new tags. Make the GHCR package public, or every pull will need
docker login ghcr.io with a PAT on each deploy host.
Connecting a client
Claude Code
claude mcp add streamystats -s user --transport http http://<docker-host>:8940/mcp \
--header "Authorization: Bearer <MCP_AUTH_TOKEN>"(Drop the --header flag if you're running with MCP_AUTH_TOKEN unset.)
Claude Desktop
{
"mcpServers": {
"streamystats": {
"command": "npx",
"args": [
"-y", "mcp-remote", "http://<docker-host>:8940/mcp",
"--header", "Authorization: Bearer <MCP_AUTH_TOKEN>"
]
}
}
}Running without Docker
pip install -r requirements.txt
STREAMYSTATS_URL=http://192.168.1.50:3000 STREAMYSTATS_JELLYFIN_TOKEN=your-jellyfin-key \
MCP_AUTH_TOKEN=your-shared-secret python server.pyTesting
pip install -r requirements-dev.txt
python -m pytest tests/ -vtests/test_tools.py— each tool's logic against a mocked Streamystats (httpx.MockTransport, no extra mocking library needed).tests/test_http.py—/health,/ready, and the bearer-auth middleware, viaserver.build_app()(the exact app__main__runs) through Starlette'sTestClient.tests/test_live_streamystats.py— opt-in contract tests against a real Streamystats instance, to catch this server's biggest real risk: that an upgrade removes or re-authenticates the undocumented endpoints this whole integration depends on. Skipped by default (no Streamystats in CI); run with:RUN_LIVE_STREAMYSTATS_TESTS=1 STREAMYSTATS_URL=https://streamystats.example.com \ STREAMYSTATS_JELLYFIN_TOKEN=<real jellyfin api key> python -m pytest tests/test_live_streamystats.py -v
CI (.github/workflows/ci.yml) runs the mocked suite on every push/PR; the
GHCR build only runs after it passes.
License
MIT
This server cannot be deployed
Maintenance
Related MCP Connectors
Analytics for MCP servers. Query your tool calls, first-call success, retries and schema cost.
Manage feature requests, votes, roadmaps, and changelogs from any MCP client.
MCP registry & directory: search, find & install 31k+ MCP servers & tools. Catalog and marketplace.
Discover MCP servers and A2A agents; verify, message, post, follow, react, and receive webhooks.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceAn MCP (Multi-Agent Conversation Protocol) Server that enables interaction with Jellyfin media server APIs, auto-generated using AG2's MCP builder based on the Jellyfin OpenAPI specification.1-
- FlicenseAqualityBmaintenanceEnables interaction with Jellyseerr media request systems through natural language. Supports searching for media, creating requests, checking request status, and managing your media library workflow.58-
- FlicenseNot gradedqualityDmaintenanceProvides interaction with Jellyfin media server via the Jellyfin REST API, enabling content management and server configuration through natural language.4-
- AlicenseAqualityDmaintenanceMCP server for managing a media server stack (Plex, Radarr, Overseerr, Bazarr, Prowlarr, Trakt.tv) using natural language to browse, request, and discover content.12MIT