mcpField
T
Task tracking (sessions, ETA, dashboard)

Task tracking (sessions, ETA, dashboard)

本地服务
github.com生产力02 周前更新

关于 Task tracking (sessions, ETA, dashboard)

面向 Claude、Lyra 等 MCP 客户端的本地长任务跟踪服务,提供会话进度、速度、预计剩余时间和终端仪表盘。还可通过本地 HTTP API 及轮询器共享任务状态,并自动跟踪 qBittorrent 和 Bazarr。

主要功能

  1. 01跟踪任务会话、步骤与日志
  2. 02计算速度、预计剩余时间和停滞状态
  3. 03提供本地 HTTP API 与终端仪表盘
  4. 04通过轮询器跟踪 qBittorrent 和 Bazarr
  5. 05使用本地 JSON 文件保存状态

适用场景

  1. 01查看下载或转换任务的实时进度
  2. 02让 Agent 启动任务后稍后检查状态
  3. 03发现长时间没有更新的运行会话
  4. 04在仪表盘中筛选和管理任务会话

MCP 相关

作为 MCP 服务,为客户端提供长任务会话的跟踪和管理工具。会话状态也能通过本地 HTTP API 与脚本及轮询器共享。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"amineutron-mcp-tracking": {
"command": "uvx",
"args": [
"mcp-tracking"
],
"env": {
"TRACKING_STATE_DIR": "<TRACKING_STATE_DIR>",
"TRACKING_TOKEN_FILE": "<TRACKING_TOKEN_FILE>"
}
}
}
}
启动命令uvx mcp-tracking
需要配置的环境变量
TRACKING_STATE_DIRDirectory of the shared state file (default: XDG state dir)
TRACKING_TOKEN_FILE密钥File holding the local token required by the HTTP API

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
pypimcp-tracking0.2.1

工具

12

收录的工具列表 · 更新于 2 周前

参数类型必填说明
pidany否
namestring是
unitstring否
extraany否
itemsany否
totalnumber是
templatestring是

详细介绍

MCP Tracking

tests License: MIT Python 3.11+

英文摘要。 以本地为先的长时任务跟踪:一个供 Claude 或 Lyra 使用的 MCP 服务、一个运行于 127.0.0.1:8765 的小型 HTTP API,以及一个 Textual 终端仪表板。会话包含项目、进度、日志和模板(download、machine、free、lyra_task、movie);轮询器会自动为 qBittorrent 和 Bazarr 会话提供数据。安装:pip install .,然后运行 mcp-tracking、mcp-tracking-api、mcp-tracking-ui。无需云服务,也无遥测。

实时跟踪 MCP 服务,附带终端仪表板。 允许 Claude/Lyra 跟踪任意长时操作,并从 media-server(qBittorrent、Bazarr、DV 转换)自动为会话提供数据。


为何专为大模型 Agent 设计

启动长时任务(转换、克隆 VM、下载)的大模型 Agent 无法一直等待任务完成,也看不到两轮交互之间发生的事情。此服务为其提供共享的工作记忆:

  • 共享的进度总线。 Agent、Shell 脚本和轮询器都写入相同的会话(MCP 工具或 127.0.0.1:8765 上的本地 HTTP API):Agent 启动任务、交出控制权,之后再通过 tracking_get 读取状态。
  • 计算得出的指标,而非猜测。 2 分钟平滑速度、预计剩余时间、已用时间(metrics.py):Agent 获取的是具体数据,无需自行推算。
  • 无响应的任务一目了然。 running 会话若 10 分钟没有更新,就会标记为 stale:Agent 可以区分“仍在运行”和“进程已终止”。
  • 停止时针对正确的进程。 会话可以记录其进程的 pid;从 /proc 读取的启动时间可避免误报被其他程序复用的 pid。tracking_stop 发送 SIGTERM 并保留会话,tracking_kill 发送 SIGKILL 并删除会话。
  • 不会丢失更新。 状态存储在本地 JSON 文件中,由 flock 锁保护并以原子方式重写(storage.py):多个 Agent 和脚本可以同时写入。
  • 按任务类型提供模板(download、machine、movie、lyra_task、free),让每个 Agent 都能以相同方式描述任务。

以本地为先且可自托管:无需云服务、无遥测,所有数据都保留在本机(on-prem)。Lyra(链接)这个法语优先的语音助手,以及任意 MCP 客户端(Claude Code、Claude Desktop 等)都在使用。

演示

由测试模式模拟数据填充的终端仪表板

通过 docs/demo/record.sh 录制:server.py --test 在临时状态目录(TRACKING_STATE_DIR)中填充四个模拟会话,然后 server.py --ui 在该目录上打开仪表板。不会影响真实会话。

目录


架构

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)
状态和配置文件
文件位置覆盖项
tracking_state.json~/.local/state/tracking/TRACKING_STATE_DIR
poller_state.json~/.local/state/tracking/TRACKING_STATE_DIR
templates.json(用户模板,可选)~/.config/tracking/TRACKING_TEMPLATES_FILE
credentials/*.cred(qBittorrent、Bazarr)与代码位于同一目录,已加入 gitignore--

与代码位于同一目录的旧版 tracking_state.json 会在首次启动时自动迁移(复制,不会删除)。

保留期限环境变量:

变量默认值作用
TRACKING_TTL_DAYS7清理已完成 / 出错 / 已暂停的会话
TRACKING_TTL_RUNNING_H24清理已失联的运行中会话(不再更新)
完整数据流
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)

状态文件在每次修改时都会通过原子写入(os.replace)并在文件锁(tracking_state.lock)保护下写入。所有进程(MCP、API、轮询器、仪表盘)共用这一个文件;每次读取时都会检查 mtime,以使缓存失效。

所有变更操作(HTTP 或 MCP)都会经过 mutations.py,确保两种路径的行为一致:为条目和会话设置 started_at / finished_at,记录进度历史(40 个点的滑动窗口),设置 info / warn / error 日志级别,并在所有条目都完成时自动完成会话。

派生指标

GET /sessions 和 tracking_get 会返回一个由 metrics.py 即时计算的 metrics 块:

字段含义
percent进度(最高为 100)
rate、rate_str最近 120 秒的速度(2.0 MB/s、30.0 u/min)
eta_seconds、eta_str预计剩余时间(仅适用于运行中的会话)
elapsed_seconds、elapsed_str从 created_at 到 finished_at 或当前时间的时长
idle_seconds、stalestale = 运行中但 10 分钟没有更新(显示在 TUI 中)

一行安装

uvx mcp-tracking          # serveur MCP (stdio) ; avant publication : uvx --from git+https://github.com/amineutron/mcp-tracking mcp-tracking
uvx --from mcp-tracking mcp-tracking-api   # API HTTP 127.0.0.1:8765
uvx --from mcp-tracking mcp-tracking-ui    # tableau de bord terminal

Claude Desktop / Claude Code 配置(mcpServers):

{ "tracking": { "command": "uvx", "args": ["mcp-tracking"] } }

安装

cd <dossier du dépôt>

# 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"

MCP 已在 Claude Code 中注册(用户范围):

claude mcp list        # -> tracking: Connected

重新注册:

claude mcp add tracking -s user -- \
  <dossier du dépôt>/.venv/bin/python \
  <dossier du dépôt>/server.py

systemd 服务

两个服务持续运行,并在系统启动时启动:

服务作用端口
tracking-api.service为外部脚本提供本地 HTTP API127.0.0.1:8765
tracking-poller.service轮询 qBittorrent(10 秒)+ Bazarr(60 秒)--
初次安装和重新部署
cd <dossier du dépôt>
./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

已由 Claude Code 会话打开的 MCP server.py 实例不会被 deploy.sh 重启:在这些会话中通过 /mcp 重新连接 tracking。

常用命令
# 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

启动

仪表盘(wofi 快捷方式)

在 wofi/launcher 中搜索“MCP Tracking”。仪表盘将在 Kitty 中启动。

仪表盘(终端)
# Toutes les sessions
<dossier du dépôt>/.venv/bin/python \
  <dossier du dépôt>/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
通过 MCP 工具(从 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
测试模式(演示)
.venv/bin/python server.py --test

并行模拟 4 个会话:下载、机器(12 个节点)、free、电影(完整 DV 流程)。


仪表盘

会话布局
[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               --
  --                                    --
  --                                    --
条目图标
图标状态颜色
[ ]待处理灰色
[>]运行中青色
[ok]已完成绿色
[!]出错红色
会话颜色
颜色状态
青色运行中
绿色已完成
红色出错
黄色已暂停
键盘快捷键
按键操作
f下一个筛选条件(按模板动态循环)
e切换为仅显示错误的筛选条件
r手动刷新
s正常停止会话(输入 ID)-> 状态为 paused
k强制终止会话(输入 ID)-> 删除
q退出
方向键 / 滚轮滚动
停止/终止模态框

按 s 或 k 会打开一个模态框,其中有一个会话 ID 输入框。

  • s 将会话标记为 paused 并添加一条日志
  • k 从仪表板中永久删除会话
  • Echap 取消
动态筛选

筛选条件循环会根据当前存在的会话自动构建:

all -> download -> free -> movie -> lyra_task -> errors -> all -> ...
  • all 始终存在
  • JSON 中存在的每个模板都会自动添加
  • 只有至少有一个会话出错时才会显示 errors
  • 活动筛选条件显示在副标题中:filtre: movie | 2/5 session(s)
  • 如果筛选的模板从 JSON 中消失,则自动返回 all

与 media-server 集成

qBittorrent(自动)

轮询器每 10 秒查询一次 http://localhost:8080/api/v2/torrents/info。

  • 一个活动种子 = 一个 [DOWNLOAD] 会话,包含名称、大小、速度和预计剩余时间
  • 种子完成或消失后,会话会自动删除
  • 凭据:credentials/qbt-password.cred(使用 systemd-creds --user 加密,由 media-server/scripts/secrets/rotate-secrets.sh 生成)
Bazarr 缺失字幕(自动)

轮询器每 60 秒查询一次 Bazarr API。

  • 一个唯一的 [SUBTITLES] 会话列出所有缺少法语字幕的剧集/电影
  • 会话标题显示总数:Sous-titres manquants (151)
  • 前 50 个缺失文件会列为条目
  • Bazarr API 密钥:credentials/bazarr-api-key.cred(相同机制)。没有凭据时,相关轮询会直接禁用。
Dolby Vision 转换(自动)

Radarr/Sonarr 导入 Dolby Vision Profile 4 或 7 的电影时,由 dv-webhook.service 触发。

流程:

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

跟踪的 6 个步骤及其指标:

步骤工具显示的指标
1/6 提取 HEVCffmpeg帧 / 速度 / 大小 / 时间
2/6 解复用 BL/ELdovi_tool帧 X/Y (%),bl:X GB,el:X GB
3/6 提取 RPU + 转换为 P8dovi_tool帧 X/Y (%),RPU:X KB
4/6 将 RPU P8 注入 BLdovi_tool帧 X/Y (%),P8 HEVC:X GB
5/6 重建时间戳ffmpeg帧 / fps / 大小
6/6 最终 MKV 重新封装ffmpeg帧 / 速度 / 大小

每个步骤执行期间,全局进度条会持续前进 (不会在每个步骤结束时才按 1/6 跳跃)。

手动模式:

# Fichier unique
python <media-server>/scripts/dv_convert.py /chemin/film.mkv

# Scan dossier
python <media-server>/scripts/dv_convert.py --scan /mnt/media/media/movies

在手动模式下,跟踪会话会在 process_file 中自动创建。

本地 HTTP API(端口 8765)

外部脚本可以直接创建/修改会话:

# 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

完整 PUT 请求体(所有字段均为可选):

{
  "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 工具

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

添加日志,但不修改进度。

Parametres:
  session_id  (str)
  message     (str)
tracking_complete

将状态标记为 done,进度设为 100%。

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

标记为出错(自动添加前缀 “ERREUR:”,并显示在“错误”列中)。

Parametres:
  session_id  (str)
  message     (str)
tracking_stop

正常停止会话(状态 -> paused)。会话仍会显示在仪表板中。

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

强制删除会话。会话会立即从仪表板中消失。

Parametres:
  session_id  (str)
tracking_get

返回格式化的会话完整状态。

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

删除会话(等同于 tracking_kill)。

tracking_templates

显示模板列表及其字段。

open_tracking_ui

在 Kitty 终端中打开仪表板。

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

模板

download

文件下载。由 qBittorrent 通过轮询器自动填充。

Champs extra : speed, eta
Unite par defaut : MB
machine

机器操作(更新、克隆、快照、部署)。 Lyra 用于 VM/集群操作。

Champs extra : operation, target
Unite par defaut : machines
free

自由格式。轮询器用于查找缺失的 Bazarr 字幕。

Aucun champ extra impose, aucune unite par defaut.
lyra_task

Lyra 操作(VM 克隆、备份、更新、快照)。

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

完整的电影流水线:下载 -> Dolby Vision 转换。 当 Radarr/Sonarr 导入 DV P4/P7 文件时,由 dv_convert.py 自动填充。

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"

安全

威胁模型

桌面机器上两种现实的攻击者:

  1. 在浏览器中打开的网页。“localhost 不是安全边界”:网页可以向 127.0.0.1:8765 发送请求。没有保护的话,它可能创建或删除会话,尤其是请求向某个进程发送信号。
  2. 另一个本地用户(或遭到入侵的服务),试图读取状态或控制 API。
措施
  • api.py 仅监听 127.0.0.1:8765——无法从网络访问
  • 写入时必须提供本地令牌:首次启动时在 $XDG_RUNTIME_DIR/tracking/token 中生成(权限为 0600,因此其他用户无法读取),对 POST、PUT 和 DELETE 请求要求通过 Authorization: Bearer ... 提供。网页无法读取该令牌。
  • 拒绝浏览器请求:任何 Origin 标头都会导致 403,即使提供了令牌也一样。
  • 验证 Host 标头(仅限回环地址),写入时必须提供 Content-Type: application/json。
  • 信号仅可发送给由服务注册的进程:创建会话时,服务会验证所声明的 pid 是否存在且属于同一用户,然后记录其启动时间。若进程指纹已更改(进程编号被其他程序重用),或者该 pid 从未注册过,/stop 和 /kill 都会拒绝操作。无法再通过 PUT 修改 pid。每次发送的信号都会记入日志。
  • 强化 systemd 服务:ProtectSystem=strict、ProtectHome=read-only(仅状态目录可写)、PrivateTmp、SystemCallFilter=@system-service、空的 CapabilityBoundingSet=、UMask=0077。可通过 systemd-analyze security tracking-api.service 检查。
  • 已知限制:lyra-daemon 保留了用于控制机器(服务、VM、音频)的 sudo NOPASSWD。这并非 tracking 授予的权限,强化该权限属于 Lyra 项目;只要此守护进程存在,攻击者若能以该用户身份执行代码,就能获得此权限,不受上述保护措施的影响。
  • 在 docker-compose.yml 中将 n8n 限制为 127.0.0.1:5678
  • dv_webhook_server.py 监听 0.0.0.0:8787(接收 Docker webhook 所必需)——如果机器暴露在外,请使用防火墙保护此端口
  • systemd 服务以 NoNewPrivileges=true 运行
  • 代码中不含明文密钥:poller.py 读取 $CREDENTIALS_DIRECTORY(用户服务),或通过 systemd-creds decrypt --user 解密 credentials/*.cred(系统服务);调试时则回退到 QBT_PASSWORD / BAZARR_KEY 环境变量

添加模板

  1. 打开 templates.py,在 TEMPLATES 中添加一项:
"mon_template": {
    "description": "Description courte",
    "extra_fields": ["champ1", "champ2"],
    "default_unit": " unites",
    "example_extra": {"champ1": "valeur", "champ2": "valeur"},
},
  1. 可选:在 sim.py 中添加 _sim_mon_template() 模拟函数。

无需其他修改,模板即可立即使用。

也可以不修改代码,直接在 ~/.config/tracking/templates.json 中声明模板(结构相同,键为模板名称);启动时会加载该文件。


测试

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

conftest.py 中的 autouse fixture 会将持久化路径重定向到 tmp_path:测试绝不会触及生产状态。

Lyra 生态系统的一部分

仓库作用
lyra法语优先的语音助手:本地优先的语音 DevOps 助手(AGPL-3.0);它通过规则理解日常法语,甚至无需调用模型,因此只用 0.5B 模型即可满足需求
fedora-agentsMCP:KVM 虚拟机和备份
mcp-trackingMCP + API + 长时间运行任务的仪表板
neutroncore家庭实验室的 PWA 中心
hue-mcpPhilips Hue MCP(fork 自 ThomasRohde/hue-mcp)
pylips-mcpPhilips TV MCP
denon-mcpDenon 功放 MCP
catt-mcpChromecast 和 DLNA MCP

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。