Skip to main content
Glama
marouabah

tracking

by marouabah

MCP Tracking

Serveur MCP de suivi en temps reel 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).


Sommaire


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)

Fichiers d'etat et configuration

Fichier

Emplacement

Surcharge

tracking_state.json

~/.local/state/tracking/

TRACKING_STATE_DIR

poller_state.json

~/.local/state/tracking/

TRACKING_STATE_DIR

templates.json (templates utilisateur, optionnel)

~/.config/tracking/

TRACKING_TEMPLATES_FILE

credentials/*.cred (qBittorrent, Bazarr)

a cote du code, gitignore

--

Un ancien tracking_state.json a cote du code est migre automatiquement au premier demarrage (copie, jamais supprime).

Variables d'environnement de retention :

Variable

Defaut

Role

TRACKING_TTL_DAYS

7

Purge des sessions done / error / paused

TRACKING_TTL_RUNNING_H

24

Purge des sessions running orphelines (plus mises a jour)

Flux de donnees complet

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)

Le fichier d'etat est ecrit a chaque modification via ecriture atomique (os.replace) sous verrou fichier (tracking_state.lock). Tous les processus (MCP, API, poller, dashboard) partagent cet unique fichier ; chaque lecture verifie le mtime pour invalider son cache.

Toute mutation (HTTP ou MCP) passe par mutations.py, qui garantit le meme comportement sur les deux chemins : started_at / finished_at poses sur les items et la session, historique de progression (fenetre glissante de 40 points), niveaux de log info / warn / error, auto-completion quand tous les items sont termines.

Metriques derivees

GET /sessions et tracking_get renvoient un bloc metrics calcule a la volee par metrics.py :

Champ

Sens

percent

progression (plafonnee a 100)

rate, rate_str

vitesse sur les 120 dernieres secondes (2.0 MB/s, 30.0 u/min)

eta_seconds, eta_str

temps restant estime (session running uniquement)

elapsed_seconds, elapsed_str

depuis created_at jusqu'a finished_at ou maintenant

idle_seconds, stale

stale = running sans mise a jour depuis 10 min (affiche dans le 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"

Le MCP est enregistre dans Claude Code (scope user) :

claude mcp list        # -> tracking: Connected

Pour reenregistrer :

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

Services systemd

Deux services tournent en permanence et se lancent au boot :

Service

Role

Port

tracking-api.service

API HTTP locale pour scripts externes

127.0.0.1:8765

tracking-poller.service

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

--

Installation initiale et redeploiement

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

Les instances MCP server.py deja ouvertes par des sessions Claude Code ne sont pas redemarrees par deploy.sh : reconnecter tracking via /mcp dans ces sessions.

Commandes utiles

# 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

Lancement

Dashboard (raccourci wofi)

Cherche "MCP Tracking" dans wofi/launcher. Lance le dashboard dans 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 outil MCP (depuis 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

Mode test (demo)

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

Simule 4 sessions en parallele : download, machine (12 noeuds), free, movie (pipeline DV complet).


Dashboard

Layout d'une session

[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               --
  --                                    --
  --                                    --

Icones items

Icone

Statut

Couleur

[ ]

pending

gris

[>]

running

cyan

[ok]

done

vert

[!]

error

rouge

Couleurs de session

Couleur

Statut

cyan

running

vert

done

rouge

error

jaune

paused

Raccourcis clavier

Touche

Action

f

Filtre suivant (cycle dynamique par template)

e

Basculer filtre erreurs uniquement

r

Refresh manuel

s

Stop propre d'une session (saisir l'ID) -> status paused

k

Kill force d'une session (saisir l'ID) -> suppression

q

Quitter

Fleches / Molette

Scroll

Modales stop/kill

Appuyer sur s ou k ouvre un modal avec un champ de saisie pour l'ID de session.

  • s marque la session en paused et ajoute un log

  • k supprime definitivement la session du dashboard

  • Echap annule

Filtrage dynamique

Le cycle de filtres est construit automatiquement depuis les sessions presentes :

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

  • Chaque template present dans le JSON s'ajoute automatiquement

  • errors n'apparait que si au moins une session a une erreur

  • Filtre actif affiche dans le sous-titre : filtre: movie | 2/5 session(s)

  • Si le template filtre disparait du JSON, retour automatique a all


Integration media-server

qBittorrent (automatique)

Le poller interroge http://localhost:8080/api/v2/torrents/info toutes les 10 secondes.

  • Un torrent actif = une session [DOWNLOAD] avec nom, taille, vitesse, ETA

  • La session est supprimee automatiquement quand le torrent termine ou disparait

  • Credentials : credentials/qbt-password.cred (chiffre systemd-creds --user, genere par media-server/scripts/secrets/rotate-secrets.sh)

Bazarr sous-titres manquants (automatique)

Le poller interroge l'API Bazarr toutes les 60 secondes.

  • Une session [SUBTITLES] unique liste tous les episodes/films sans sous-titres FR

  • Le titre de la session indique le total : Sous-titres manquants (151)

  • Les 50 premiers fichiers manquants sont listes comme items

  • API key Bazarr : credentials/bazarr-api-key.cred (meme mecanisme). Sans credential, le poll concerne est simplement desactive.

Conversion Dolby Vision (automatique)

Declenche par dv-webhook.service quand Radarr/Sonarr importent un film DV Profile 4 ou 7.

Flux :

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

Les 6 etapes trackees avec leurs metriques :

Etape

Outil

Metriques affichees

1/6 extraction HEVC

ffmpeg

frame / speed / size / time

2/6 demux BL/EL

dovi_tool

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

3/6 extraction RPU + conv P8

dovi_tool

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

4/6 injection RPU P8 dans BL

dovi_tool

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

5/6 reconstruction timestamps

ffmpeg

frame / fps / size

6/6 remuxage MKV final

ffmpeg

frame / speed / size

La barre de progression globale avance en continu pendant chaque etape (pas par sauts de 1/6 a la fin de chaque etape).

Mode manuel :

# 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

En mode manuel, la session tracking est creee automatiquement dans process_file.

API HTTP locale (port 8765)

Scripts externes peuvent creer/modifier des sessions directement :

# 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

Corps PUT complet (tous les champs optionnels) :

{
  "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
  }
}

Outils MCP

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

Ajoute un log sans modifier la progression.

Parametres:
  session_id  (str)
  message     (str)

tracking_complete

Marque done a 100%.

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

tracking_error

Marque en erreur (prefixe "ERREUR:" auto, remonte dans colonne Erreurs).

Parametres:
  session_id  (str)
  message     (str)

tracking_stop

Arrete proprement une session (status -> paused). Reste visible dans le dashboard.

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

tracking_kill

Supprime une session en force. Disparait immediatement du dashboard.

Parametres:
  session_id  (str)

tracking_get

Retourne l'etat complet formate d'une session.

tracking_list

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

tracking_delete

Supprime une session (equivalent de tracking_kill).

tracking_templates

Affiche la liste des templates et leurs champs.

open_tracking_ui

Ouvre le dashboard dans un terminal Kitty.

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

Templates

download

Telechargement de fichiers. Alimente automatiquement par qBittorrent via le poller.

Champs extra : speed, eta
Unite par defaut : MB

machine

Operations sur des machines (update, clone, snapshot, deploy). Utilise par Lyra pour les operations VM/cluster.

Champs extra : operation, target
Unite par defaut : machines

free

Format libre. Utilise par le poller pour les sous-titres Bazarr manquants.

Aucun champ extra impose, aucune unite par defaut.

lyra_task

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

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

movie

Pipeline complet d'un film : telechargement -> conversion Dolby Vision. Alimente automatiquement par dv_convert.py quand Radarr/Sonarr importent un fichier DV P4/P7.

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"

Securite

  • api.py ecoute uniquement sur 127.0.0.1:8765 -- inaccessible depuis le reseau

  • n8n restreint a 127.0.0.1:5678 dans docker-compose.yml

  • dv_webhook_server.py ecoute sur 0.0.0.0:8787 (necessaire pour recevoir les webhooks Docker) -- proteger ce port avec un firewall si la machine est exposee

  • Les services systemd tournent avec NoNewPrivileges=true

  • Aucun secret en clair dans le code : poller.py lit $CREDENTIALS_DIRECTORY (service user) ou dechiffre credentials/*.cred via systemd-creds decrypt --user (service systeme), avec repli sur les variables QBT_PASSWORD / BAZARR_KEY pour le debug


Ajouter un template

  1. Ouvrir templates.py et ajouter une entree dans TEMPLATES :

"mon_template": {
    "description": "Description courte",
    "extra_fields": ["champ1", "champ2"],
    "default_unit": " unites",
    "example_extra": {"champ1": "valeur", "champ2": "valeur"},
},
  1. Optionnel : ajouter une simulation _sim_mon_template() dans sim.py.

Le template est immediatement disponible sans autre modification.

Sans toucher au code, un template peut aussi etre declare dans ~/.config/tracking/templates.json (meme structure, cle = nom du template) ; il est charge au demarrage.


Tests

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

La fixture autouse de conftest.py redirige la persistence vers un tmp_path : les tests ne touchent jamais l'etat de production.

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