Skip to main content
Glama
marouabah

tracking

by marouabah

MCP Tracking

Server MCP de suivi en temps réel avec dashboard terminal. Permet a Claude/Lyra de tracker n'importe quelle operation longue ET alimente automatiquement les sessions depuis le media-server (qBittorrent, Bazarr, conversion DV).

Wait, I need to translate to English, not reproduce French. Let's do the actual final translation.


MCP Tracking

Real-time MCP tracking server with a terminal dashboard. Allows Claude/Lyra to track any long-running operation AND automatically feeds sessions from the media-server (qBittorrent, Bazarr, DV conversion).


Table of Contents


Related MCP server: Claude Session MCP

Architecture

MCP/tracking/
  server.py              -- Serveur MCP (outils Claude/Lyra) + point d'entree --ui / --test
  api.py                 -- API HTTP locale (127.0.0.1:8765) pour les scripts externes
  mutations.py           -- Mutations d'une session, partagees par api.py ET server.py
                            (horodatage items, historique, niveaux de log, auto-completion)
  metrics.py             -- Metriques derivees (vitesse, ETA, ecoule, stale) -- logique pure,
                            calculees a la lecture, jamais stockees
  storage.py             -- Persistence JSON atomique + verrou fichier + cache mtime + purge TTL
  models.py              -- Modeles pydantic (TrackingSession, TrackingItem, LogEntry, ProgressPoint)
  templates.py           -- Templates builtin + templates utilisateur (JSON)
  ui.py                  -- Dashboard Textual (TUI temps reel) + modales stop/kill
  sim.py                 -- Simulations de demo (server.py --test)
  poller.py              -- Daemon polling qBittorrent (10s) + Bazarr (60s)
  tracking-api.service   -- Unite systemd (systeme) pour api.py
  tracking-poller.service -- Unite systemd (systeme) pour poller.py
  install.sh / deploy.sh -- Installation initiale / redeploiement des services
  Makefile               -- make test | smoke | deploy | ui
  tests/                 -- unitaires (storage, metrics) + integration/ (API HTTP reelle)

State and configuration files

File

Location

Override

tracking_state.json

~/.local/state/tracking/

TRACKING_STATE_DIR

poller_state.json

~/.local/state/tracking/

TRACKING_STATE_DIR

templates.json (user templates, optional)

~/.config/tracking/

TRACKING_TEMPLATES_FILE

credentials/*.cred (qBittorrent, Bazarr)

next to the code, gitignored

--

An old tracking_state.json next to the code is automatically migrated at first startup (copied, never deleted).

Retention envirnoment variables:

Variable

Default

Role

TRACKING_TTL_DAYS

7

Purge sessions with status done / error / paused

TRACKING_TTL_RUNNING_H

24

Purge orphanned running sessions (no longer updated)

Complete data flow

Claude/Lyra (outils MCP)
      |
      v
  server.py ─────────────────────────────────────────┐
                                                      |
qBittorrent API (poll 10s)                            |
      |                                               |
Bazarr API (poll 60s)    ──> poller.py ──> api.py ──> mutations.py ──> storage.py ──> ~/.local/state/tracking/tracking_state.json
      |                                               |                        |
dv_webhook_server.py                                  |                        v
      |                                               |                     ui.py
      v                                               |               (rafraichit chaque seconde)
dv_convert.py ──────────────────────────────────────>
   (metriques temps reel ffmpeg/dovi_tool)

The state file is written on every change via atomic write (os.replace) under a file lock (tracking_state.lock). All processes (MCP, API, poller, dashboard) share this single file; every read checks the mtime to invalide its cache.

Every mutation (HTTP or MCP) goes through mutations.py, which guarantees the same behavior on both paths: started_at / finished_at set on items and the session, progress history (slding window of 40 points), info / warn / error log levels, auto-completion when all items are finished.

Derived metrics

GET /sessions and tracking_get return a metrics block computed on the fly by metrics.py:

Field

Meaning

percent

progress (capped at 100)

rate, rate_str

speed over the last 120 seconds (2.0 MB/s, 30.0 u/min)

eta_seconds, eta_str

estimated time remaining (running session only)

elapsed_seconds, elapsed_str

from created_at to finished_at or now

idle_seconds, stale

stale = running without an update for 10 min (shown in the TUI)


Installation

cd /home/amineutron/dev/MCP/tracking

# Creer le venv et installer les dependances
uv venv .venv
uv pip install "mcp[cli]>=1.0.0" "pydantic>=2.0" "textual>=0.80.0" "fastapi"

The MCP is registered in Claude Code (user scope):

claude mcp list        # -> tracking: Connected

To re-register:

claude mcp add tracking -s user -- \
  /home/amineutron/dev/MCP/tracking/.venv/bin/python \
  /home/amineutron/dev/MCP/tracking/server.py

systemd Services

Two services run permanently and start at boot:

Service

Role

Port

tracking-api.service

Local HTTP API for external scripts

127.0.0.1:8765

tracking-poller.service

Polls qBittorrent (10s) + Bazarr (60s)

--

Initial installation and redeployment

cd /home/amineutron/dev/MCP/tracking
./install.sh        # premiere fois : venv + services (demande sudo)
sudo ./deploy.sh    # apres chaque mise a jour du code : stop, unites, restart, verif
make smoke          # sante rapide

MCP instances of server.py already open by Claude Code sessions are not restarted by deploy.sh: reconnect tracking via /mcp in those sessions.

Useful commands

# Etat
systemctl status tracking-api.service tracking-poller.service

# Logs en direct
journalctl -fu tracking-poller.service
journalctl -fu tracking-api.service

# Redemarrage
sudo systemctl restart tracking-api.service tracking-poller.service

# Test API
curl http://127.0.0.1:8765/health
curl http://127.0.0.1:8765/sessions

Launch

Dashboard (wofi shortcut)

Search for "MCP Tracking" in wofi/launcher. Launch the dashboard in Kitty.

Dashboard (terminal)

# Toutes les sessions
/home/amineutron/dev/MCP/tracking/.venv/bin/python \
  /home/amineutron/dev/MCP/tracking/server.py --ui

# Filtre direct au lancement
.venv/bin/python server.py --ui --filter download
.venv/bin/python server.py --ui --filter movie
.venv/bin/python server.py --ui --filter errors

Via MCP tool (from Claude/Lyra)

open_tracking_ui()                             # toutes les sessions
open_tracking_ui(filter_template="lyra_task")  # vue Lyra uniquement
open_tracking_ui(filter_template="errors")     # erreurs uniquement

Test mode (demo)

.venv/bin/python server.py --test

Simulates 4 sessions in parallel: download, machine (12 nodes), free, movie (complete DV pipeline).


Dashboard

Session layout

[TEMPLATE]  Nom de la session  id:xxxxxxxx  (status)
  [=============>            ] 54.2%  27100 MB / 50000 MB
  champ_extra1: valeur  |  champ_extra2: valeur

  [ok]  item-1                          100.0 GB     -- termine
  [>]   item-2                          frame: 94231 / 172800  (54.5%)  speed: 3.2x
  [ ]   item-3                          --
  [!]   item-4                          erreur detail

  Logs                                  Erreurs
  14:32:01  Message log 1               [!] item-4
  14:32:04  Message log 2               14:32:08  ECHEC: details
  14:32:07  Message log 3               --
  --                                    --
  --                                    --

Item icons

Icon

Status

Color

[ ]

pending

gray

[>]

running

cyan

[ok]

done

green

[! ]

error

red

Session colors

Color

Status

cyan

running

green

done

red

error

yellow

paused

Keyboard shortcuts

Key

Action

f

Next filter (dynamic cycle by template)

e

Toggle errors-only filter

r

Manual refresh

s

Clean stop of a session (enter the ID) -> status paused

k

Force kill a session (enter the ID) -> deletion

q

Quit

Arrows / Wheel

Scroll

Stop/kill modals

Pressing s or k opens a modal with an input field for the session ID.

  • s marks the session as paused and adds a log

  • k permanently deletes the session from the dashboard

  • Esc cancels

Dynamic filtering

The filter cycle is built automatically from the sessions present:

all -> download -> free -> movie -> lyra_task -> errors -> all -> ...
  • all always present

  • Each template present in the JSON is added automatically

  • errors appears only if at least one session has an error

  • Active filter displayed in the subtitle: filter: movie | 2/5 session(s)

  • If the filtered template disappears from the JSON, automatic return to all


media-server Integration

qBittorrent (automatic)

The poller queries http://localhost:8080/api/v2/torrents/info every 10 seconds.

  • An active torrent = a [DOWNLOAD] session with name, size, speed, ETA

  • The session is automatically deleted when the torrent finishes or disappears

  • Credentials: credentiales/qbt-password.cred (encrypted with systemd-creds --user, generated by media-server/scripts/secrets/rotate-secrets.sh)

Bazarr missing subtitles (automatic)

The poller queries the Bazarr API every 60 seconds.

  • A single [SUBTITLES] session lists all episodes/movies without French subtitles

  • The session title shows the total: Sous-titres manquants (151)

  • The first 50 missing files are listed as items

  • Bazarr API key: credentiales/bazarr-api-key.cred (same mechanism). Without a credential, that poll is simply disabled.

Dolby Vision conversion (automatic)

Triggered by dv-webhook.service when Radarr/Sonarr import a DV Profile 4 or 7 movie.

Flow:

Radarr/Sonarr import
      |
      v
dv_webhook_server.py (port 8787)
      |-- cree session tracking via api.py
      |-- passe DV_TRACKING_SESSION_ID en env
      v
dv_convert.py
      |-- 6 etapes avec metriques temps reel
      |-- ffmpeg   : frame / speed / size / time (parse stderr)
      |-- dovi_tool: frames X/Y ou X% (parse stderr indicatif)
      v
session tracking completee ou en erreur

The 6 tracked steps with their metrics:

Step

Tool

Metrics shown

1/6 HEVC extraction

ffmpeg

frame / speed / size / time

2/6 BL/EL demux

dovi_tool

frames X/Y (%), bl: X GB, el: X GB

3/6 RPU extraction + P8 conversion

dovi_tool

frames X/Y (%), RPU: X KB

4/6 RPU P8 injection into BL

dovi_tool

frames X/Y (%), P8 HEVC: X GB

5/6 timestamp reconstruction

ffmpeg

frame / fps / size

6/6 final MKV remux

ffmpeg

frame / speed / size

The overall progress bar advances continuously during each step (not in jumps of 1/6 at the end of each step).

Manual mode:

# Fichier unique
python /home/amineutron/dev/media-server/scripts/dv_convert.py /chemin/film.mkv

# Scan dossier
python /home/amineutron/dev/media-server/scripts/dv_convert.py --scan /mnt/media/media/movies

In manual mode, the tracking session is automatically created in process_file.

Local HTTP API (port 8765)

External scripts can create/modify sessions directly:

# Creer une session
curl -X POST http://127.0.0.1:8765/sessions \
  -H "Content-Type: application/json" \
  -d '{"name":"Mon operation","template":"free","total":100,"unit":"%"}'
# -> {"id": "a1b2c3d4"}

# Mettre a jour
curl -X PUT http://127.0.0.1:8765/sessions/a1b2c3d4 \
  -H "Content-Type: application/json" \
  -d '{"processed":45,"log":"Etape 2/5 en cours","extra":{"phase":"etape 2"}}'

# Mettre a jour un item
curl -X PUT http://127.0.0.1:8765/sessions/a1b2c3d4 \
  -H "Content-Type: application/json" \
  -d '{"item":{"name":"mon-item","status":"done","note":"100 frames  speed: 2x"}}'

# Supprimer
curl -X DELETE http://127.0.0.1:8765/sessions/a1b2c3d4

# Lister
curl http://127.0.0.1:8765/sessions

Complete PUT body (all fields optional):

{
  "processed": 45.0,
  "total":     100.0,
  "status":    "running",
  "extra":     {"phase": "etape 2"},
  "log":       "message de log",
  "item": {
    "name":      "nom-de-l-item",
    "status":    "running",
    "note":      "metriques ici",
    "processed": 50.0,
    "total":     100.0
  }
}

MCP Tools

tracking_create

Parametres:
  name      (str)          Nom de la session
  template  (str)          "download" | "machine" | "free" | "movie" | "lyra_task" |
                           "subtitles" | "series_episode" | "series_season" | template utilisateur
  total     (float)        Valeur totale
  unit      (str, opt)     Unite affichee (ex: " MB", " machines", "%")
  items     (list, opt)    Liste d'elements a suivre
  extra     (dict, opt)    Champs specifiques au template

Format items:
  [{"name": "fichier.iso", "total": 5100, "unit": " MB", "note": "info"}]

Retourne: ID de session + etat initial formate

tracking_update

Parametres:
  session_id    (str)          ID de la session
  processed     (float, opt)   Nouvelle valeur de progression
  message       (str, opt)     Message de log
  item_updates  (list, opt)    Mises a jour des items
  extra         (dict, opt)    Champs extra a merger

Format item_updates:
  [{"name": "item-1", "status": "done", "processed": 1200, "note": "detail"}]
  Status: "pending" | "running" | "done" | "error"

tracking_log

Adds a log without modifying the progression.

Parametres:
  session_id  (str)
  message     (str)

tracking_complete

Marks done at 100%.

Parametres:
  session_id  (str)
  message     (str, opt)

tracking_error

Marks as error (auto "ERREUR:" prefix, surfaced in the Erreurs column).

Parametres:
  session_id  (str)
  message     (str)

tracking_stop

Cleanly stops a session (status -> paused). Remains visible in the dashboard.

Parametres:
  session_id  (str)
  message     (str, opt)

tracking_kill

Force-deletes a session. Disapears immediately from the dashboard.

Parametres:
  session_id  (str)

tracking_get

Returns the complete formatted state of a session.

tracking_list

Parametres:
  template  (str, opt)   Filtrer par template
  status    (str, opt)   Filtrer par statut ("running", "done", "error", "paused")

tracking_delete

Deletes a session (equivalent to tracking_kill).

tracking_templates

Displays the list of templates and their fields.

open_tracking_ui

Opens the dashboard in a Kitty terminal.

Parametres:
  filter_template  (str, opt)   Template a afficher au lancement

Templates

download

File download. Automatically fed by qBittorrent via the poller.

Champs extra : speed, eta
Unite par defaut : MB

machine

Operations on machines (update, clone, snapshot, deploy). Used by Lyra for VM/cluster operations.

Champs extra : operation, target
Unite par defaut : machines

free

Free format. Used by the poller for missing Bazarr subtitles.

Aucun champ extra impose, aucune unite par defaut.

lyra_task

Lyra operations (VM clone, backup, update, snapshot).

Champs extra : operation, target, phase, eta
Unite par defaut : %

movie

Complete pipeline for a movie: download -> Dolby Vision conversion. Automatically fed by dv_convert.py when Radarr/Sonarr import a DV P4/P7 file.

Champs extra : phase, quality, codec, audio, source, dv, speed, eta
Unite par defaut : %

Les 6 etapes DV trackees avec metriques temps reel :
  "1/6 extraction HEVC"
  "2/6 demux BL/EL"
  "3/6 extraction RPU + conv P8"
  "4/6 injection RPU P8 dans BL"
  "5/6 reconstruction timestamps"
  "6/6 remuxage MKV final"

Security

  • api.py listens only on 127.0.0.1:8765 -- inaccessible from the network

  • n8n restricted to 127.0.0.1:5678 in docker-compose.yml

  • dv_webhook_server.py listens on 0.0.0.0:8787 (necessary to receive Docker webhooks) -- protect this port with a firewall if the machine is exposed

  • systemd services run with NoNewPrivileges=true

  • No plaintext secrets in the code: poller.py reads $CREDENTIALS_DIRECTORY (user service) or decrypts credentiales/*.cred via systemd-creds decrypt --user (system service), with fallback to the QBT_PASSORD / BAZARR_KEY variables for debugging


Add a template

  1. Open templates.py and add an entry to TEMPLATES:

"mon_template": {
    "description": "Description courte",
    "extra_fields": ["champ1", "champ2"],
    "default_unit": " unites",
    "example_extra": {"champ1": "valeur", "champ2": "valeur"},
},
  1. Optional: add a _ sim_mon_template() simulation in sim.py.

The template is immediately available without any other modification.

Without touching the code, a template can also be declared in ~/.config/tracking/templates.json (same structure, key = template name); it is loaded at startup.


Tests

make test     # unitaires (storage, metrics) + integration (API HTTP reelle sur port ephemere)

The autouse fixture in conftest.py redirects persistence to a tmp_path: the tests never touch the production state.

A
license - permissive license
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    Provides Claude Code with programmatic session awareness to track context usage, session history, and task progress. It enables intelligent context reset recommendations and automatic synchronization of project planning documentation.
    5
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    A comprehensive project management and workflow tracking system that integrates with Claude Code via MCP, automatically capturing sessions, tools, agents, and project tasks into a centralized dashboard and database.
    20
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    A comprehensive MCP server for monitoring Claude Code sessions, agent performance, cost tracking, project management, and GitHub synchronization with 89 tools and a real-time dashboard.

View all related MCP servers

Related MCP Connectors

  • Uptime, SSL, DNS and domain monitoring you can talk to from Claude or any MCP client.

  • Let your AI sessions talk to each other — messaging, tasks, sessions, and alerts

  • AI agent run monitoring with incident replay and SLA receipts.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/marouabah/mcp-tracking'

If you have feedback or need assistance with the MCP directory API, please join our Discord server