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
Personal assistant MCP server with search, execute, packages, jobs, secrets, and integrations.
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.
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-
- FlicenseNot gradedqualityCmaintenanceEnables interaction with Jellyseerr media request systems through natural language. Supports searching for media, creating requests, checking request status, and managing your media library workflow.8-
- 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