Daoyuan Li
cdefd4a8aa
fix(mcp): invalidate tools cache on config content + path, not just newer mtime ( #4124 )
...
* fix(mcp): invalidate tools cache on config content + path, not just newer mtime
The MCP tools cache invalidated only on a strict extensions-config mtime `>`
comparison and tracked no resolved config path, so `_is_cache_stale()` missed:
- content changes with an unchanged mtime (same-second edits; object-store /
network mounts that do not bump mtime);
- content changes with a backward mtime (git checkout, cp -p / backup restore,
tar / rsync preserving timestamps);
- a resolved-path switch to a different config file with mtime <= the recorded
value (structurally invisible — no path was tracked at all).
On multi-worker (uvicorn/gunicorn) or stale-mtime deployments this leaves the
LangGraph-embedded runtime and every non-writer worker serving stale MCP tools
after `PUT /api/mcp/config`, breaking the module's documented promise that
changes made through the Gateway API are reflected in the embedded runtime.
Record the resolved config path and a `(mtime, size, sha256)` content signature
at initialization and invalidate when the path OR the signature differs (`!=`),
mirroring `config/app_config.py::get_app_config()` so the two runtime-editable
config files share one content-based staleness signal. The per-call stat was
already paid, and the small-file sha256 matches the cost app_config pays per
request. The "config missing / not yet initialized" no-op behavior and the
cache reset endpoint are preserved.
Adds backend/tests/test_mcp_cache.py covering all three failure modes plus
unchanged-file and forward-edit sanity cases. Also folds in an incidental
backend/AGENTS.md doc-sync: the restart-required field list was missing
`scheduler` and `run_ownership`, both present in
reload_boundary.py::STARTUP_ONLY_FIELDS.
* test(mcp): pin cache staleness contracts raised in review
Two review observations on the content-signature cache fix, both raised as
non-blocking design questions rather than bugs:
- Whether relying on mtime+size alone (skipping the sha256) could ever be
"optimized" back in, reopening the narrow same-second / identical-length
swap gap the signature was built to close.
- Whether the extensions config being deleted entirely after a successful
init leaves the cache in a defined state, since current_signature flips
to None and _is_cache_stale() returns False.
Neither is a behavior change: both were already the intended contract,
preserved verbatim from the pre-fix mtime-only code (which also returned
False once the file could no longer be stat-ed). Record the reasoning
inline and add regression tests that pin each contract so a future change
cannot alter either silently:
- test_same_mtime_same_size_swap_is_stale: a same-length server-name swap
that leaves mtime AND size unchanged (the precise scenario from review,
sharper than the existing same-mtime test, which also changes size) is
still caught only because the sha256 is computed unconditionally.
- test_config_deleted_after_init_is_not_stale: deleting the config file
after init keeps the cache serving its last-known-good MCP tools instead
of invalidating into an unconfigured state.
Both new tests were confirmed to fail against a deliberately reintroduced
version of the regression they guard (hash short-circuit / removed
None-guard), then confirmed to pass against the real code.
2026-07-14 22:40:51 +08:00
..
2026-07-14 10:43:13 +08:00
2026-07-01 22:49:17 +08:00
2026-07-04 21:31:01 +08:00
2026-05-12 23:18:54 +08:00
2026-06-30 18:58:02 +08:00
2026-04-26 15:09:25 +08:00
2026-06-01 15:50:39 +08:00
2026-07-05 08:45:27 +08:00
2026-06-21 20:56:42 +08:00
2026-06-08 12:35:03 +08:00
2026-03-27 20:03:30 +08:00
2026-06-18 10:15:31 +08:00
2026-06-11 17:53:37 +08:00
2026-07-14 07:51:59 +08:00
2026-05-21 14:44:34 +08:00
2026-07-03 21:52:31 +08:00
2026-06-23 10:39:40 +08:00
2026-06-21 22:16:00 +08:00
2026-07-11 23:05:03 +08:00
2026-05-29 23:05:59 +08:00
2026-05-16 09:24:40 +08:00
2026-04-26 11:08:11 +08:00
2026-06-16 23:20:20 +08:00
2026-07-02 08:28:29 +08:00
2026-06-21 15:47:53 +08:00
2026-06-24 13:57:12 +08:00
2026-07-09 17:21:25 +08:00
2026-07-09 17:21:25 +08:00
2026-07-02 11:00:49 +08:00
2026-07-05 09:54:55 +08:00
2026-07-14 07:37:59 +08:00
2026-06-16 23:04:39 +08:00
2026-06-18 10:15:31 +08:00
2026-07-12 08:54:03 +08:00
2026-05-02 15:19:28 +08:00
2026-07-12 23:40:52 +08:00
2026-06-18 10:45:33 +08:00
2026-07-13 16:14:36 +08:00
2026-04-14 10:29:44 +08:00
2026-07-12 08:15:32 +08:00
2026-07-12 08:15:32 +08:00
2026-07-06 22:34:41 +08:00
2026-03-30 07:41:18 +08:00
2026-04-25 19:40:06 +08:00
2026-04-07 18:21:22 +08:00
2026-07-04 13:54:04 +08:00
2026-07-03 08:01:46 +08:00
2026-03-29 21:03:58 +08:00
2026-05-04 09:56:16 +08:00
2026-07-13 19:26:07 +08:00
2026-05-02 15:04:11 +08:00
2026-06-10 21:36:25 +08:00
2026-03-14 22:55:52 +08:00
2026-07-05 09:40:16 +08:00
2026-07-07 19:55:33 +08:00
2026-04-26 11:05:47 +08:00
2026-07-05 09:54:55 +08:00
2026-03-29 15:31:18 +08:00
2026-07-04 11:27:19 +08:00
2026-05-07 16:15:15 +08:00
2026-06-12 15:24:58 +08:00
2026-07-13 21:13:33 +08:00
2026-07-09 16:40:10 +08:00
2026-06-08 07:59:50 +08:00
2026-07-13 17:57:34 +08:00
2026-06-02 22:43:22 +08:00
2026-06-05 15:21:41 +08:00
2026-07-12 00:17:11 +08:00
2026-07-04 23:09:29 +08:00
2026-06-02 22:43:22 +08:00
2026-07-01 22:49:17 +08:00
2026-07-13 19:26:07 +08:00
2026-07-04 09:21:19 +08:00
2026-05-26 23:30:24 +08:00
2026-07-04 21:31:01 +08:00
2026-07-04 09:21:19 +08:00
2026-06-12 17:16:01 +08:00
2026-06-09 15:29:40 +08:00
2026-06-18 10:15:31 +08:00
2026-06-12 15:24:58 +08:00
2026-06-13 23:27:17 +08:00
2026-03-31 22:19:27 +08:00
2026-07-02 11:00:49 +08:00
2026-07-13 19:26:07 +08:00
2026-07-01 22:49:17 +08:00
2026-07-04 22:56:24 +08:00
2026-04-26 11:09:56 +08:00
2026-04-08 17:13:39 +08:00
2026-07-05 09:54:55 +08:00
2026-07-02 11:33:32 +08:00
2026-07-14 10:43:13 +08:00
2026-07-10 11:01:39 +08:00
2026-07-02 08:24:15 +08:00
2026-07-04 21:31:01 +08:00
2026-07-14 11:57:48 +08:00
2026-05-21 21:18:10 +08:00
2026-05-11 17:38:37 +08:00
2026-07-04 11:27:19 +08:00
2026-07-03 08:49:33 +08:00
2026-06-07 11:24:30 +08:00
2026-07-11 16:05:30 +08:00
2026-07-06 08:00:49 +08:00
2026-07-14 10:43:13 +08:00
2026-07-04 22:56:24 +08:00
2026-07-04 22:56:24 +08:00
2026-07-04 22:56:24 +08:00
2026-07-12 15:51:22 +08:00
2026-07-04 22:56:24 +08:00
2026-07-04 22:56:24 +08:00
2026-07-04 22:56:24 +08:00
2026-07-04 22:56:24 +08:00
2026-07-04 22:56:24 +08:00
2026-07-04 22:56:24 +08:00
2026-07-03 08:49:33 +08:00
2026-07-12 23:33:52 +08:00
2026-06-21 15:55:10 +08:00
2026-07-11 18:40:07 +08:00
2026-03-14 22:55:52 +08:00
2026-07-06 07:21:12 +08:00
2026-07-14 10:43:13 +08:00
2026-07-06 22:34:41 +08:00
2026-07-10 11:08:30 +08:00
2026-03-26 14:20:18 +08:00
2026-06-28 16:10:44 +08:00
2026-07-08 17:10:27 +08:00
2026-07-14 11:04:11 +08:00
2026-07-04 13:54:04 +08:00
2026-06-17 15:29:22 +08:00
2026-05-19 22:11:46 +08:00
2026-06-08 23:25:29 +08:00
2026-07-12 11:51:31 +08:00
2026-06-10 16:11:00 +08:00
2026-07-13 19:26:07 +08:00
2026-07-13 19:26:07 +08:00
2026-07-04 23:09:29 +08:00
2026-07-11 07:54:15 +08:00
2026-04-11 16:52:10 +08:00
2026-07-09 17:21:25 +08:00
2026-07-03 07:51:22 +08:00
2026-07-13 00:01:22 +08:00
2026-07-04 13:54:04 +08:00
2026-07-13 00:01:22 +08:00
2026-07-04 13:54:04 +08:00
2026-07-03 08:01:46 +08:00
2026-04-30 22:27:14 +08:00
2026-05-07 16:15:15 +08:00
2026-07-14 21:45:37 +08:00
2026-07-14 22:40:51 +08:00
2026-07-03 15:39:12 +08:00
2026-07-09 16:26:31 +08:00
2026-04-25 09:18:13 +08:00
2026-07-04 13:54:04 +08:00
2026-07-12 11:59:36 +08:00
2026-07-10 07:54:36 +08:00
2026-07-09 16:26:31 +08:00
2026-07-09 16:26:31 +08:00
2026-07-14 09:49:43 +08:00
2026-07-04 09:40:05 +08:00
2026-06-25 22:57:00 +08:00
2026-07-14 09:49:43 +08:00
2026-07-11 08:54:45 +08:00
2026-07-12 18:22:22 +08:00
2026-05-15 10:26:35 +08:00
2026-07-12 20:41:41 +08:00
2026-06-18 11:45:35 +08:00
2026-07-12 23:00:45 +08:00
2026-07-14 07:40:49 +08:00
2026-04-26 15:09:25 +08:00
2026-04-17 12:00:31 +08:00
2026-04-26 11:09:55 +08:00
2026-07-11 15:28:16 +08:00
2026-04-26 15:09:25 +08:00
2026-07-14 07:40:49 +08:00
2026-07-06 22:34:41 +08:00
2026-07-11 16:05:30 +08:00
2026-07-04 13:54:04 +08:00
2026-05-15 22:30:05 +08:00
2026-03-22 20:39:26 +08:00
2026-07-14 09:32:53 +08:00
2026-07-14 08:58:06 +08:00
2026-07-11 16:05:30 +08:00
2026-07-14 07:37:59 +08:00
2026-06-22 18:55:20 +08:00
2026-06-21 15:47:53 +08:00
2026-05-28 08:20:52 +08:00
2026-07-11 16:05:30 +08:00
2026-07-04 21:44:22 +08:00
2026-05-28 18:24:32 +08:00
2026-06-08 22:04:38 +08:00
2026-03-26 15:07:05 +08:00
2026-06-09 18:01:43 +08:00
2026-06-12 15:24:58 +08:00
2026-06-24 13:57:12 +08:00
2026-07-11 16:05:30 +08:00
2026-06-24 13:57:12 +08:00
2026-07-11 16:05:30 +08:00
2026-06-24 13:57:12 +08:00
2026-06-24 13:57:12 +08:00
2026-07-14 21:41:35 +08:00
2026-06-24 13:57:12 +08:00
2026-06-24 10:57:45 +08:00
2026-05-21 16:22:09 +08:00
2026-04-26 11:13:01 +08:00
2026-04-10 20:40:30 +08:00
2026-07-09 23:25:38 +08:00
2026-07-14 07:51:59 +08:00
2026-07-06 20:57:41 +08:00
2026-07-11 23:20:53 +08:00
2026-06-17 21:11:44 +08:00
2026-03-14 22:55:52 +08:00
2026-03-14 22:55:52 +08:00
2026-07-03 08:01:46 +08:00
2026-07-14 07:51:59 +08:00
2026-06-08 17:32:41 +08:00
2026-06-09 21:58:31 +08:00
2026-07-11 15:58:07 +08:00
2026-07-11 15:58:07 +08:00
2026-07-14 21:37:47 +08:00
2026-06-24 17:47:04 +08:00
2026-07-02 07:43:09 +08:00
2026-04-26 15:09:25 +08:00
2026-07-12 13:03:02 +08:00
2026-07-02 07:43:09 +08:00
2026-07-14 10:43:13 +08:00
2026-07-14 07:37:59 +08:00
2026-05-21 14:48:28 +08:00
2026-07-14 07:37:59 +08:00
2026-07-13 19:26:07 +08:00
2026-06-01 15:50:39 +08:00
2026-06-24 10:24:36 +08:00
2026-07-03 07:46:04 +08:00
2026-05-03 23:40:59 +08:00
2026-05-22 21:20:28 +08:00
2026-05-22 21:20:28 +08:00
2026-05-22 21:20:28 +08:00
2026-06-25 22:43:28 +08:00
2026-06-03 22:02:27 +08:00
2026-07-03 07:51:22 +08:00
2026-04-09 17:21:23 +08:00
2026-06-23 23:13:12 +08:00
2026-07-13 18:34:41 +08:00
2026-06-25 08:06:17 +08:00
2026-07-12 11:32:41 +08:00
2026-07-12 23:42:58 +08:00
2026-07-04 13:54:04 +08:00
2026-06-12 10:20:38 +08:00
2026-07-04 21:51:57 +08:00
2026-07-04 21:51:57 +08:00
2026-07-04 21:51:57 +08:00
2026-07-04 21:51:57 +08:00
2026-07-04 21:51:57 +08:00
2026-07-04 21:51:57 +08:00
2026-07-04 21:51:57 +08:00
2026-07-04 21:51:57 +08:00
2026-06-12 09:45:26 +08:00
2026-05-17 08:59:42 +08:00
2026-06-19 11:23:07 +08:00
2026-03-26 14:20:18 +08:00
2026-06-18 07:36:35 +08:00
2026-06-27 23:30:54 +08:00
2026-07-07 23:09:06 +08:00
2026-06-21 16:08:25 +08:00
2026-05-12 23:18:54 +08:00
2026-06-14 10:40:16 +08:00
2026-07-05 19:55:39 +08:00
2026-06-19 21:57:03 +08:00
2026-07-04 23:09:29 +08:00
2026-07-04 11:27:19 +08:00
2026-07-04 11:27:19 +08:00
2026-07-04 23:09:29 +08:00
2026-07-07 21:44:28 +08:00
2026-07-13 10:40:22 +08:00
2026-05-28 15:48:32 +08:00
2026-07-10 14:05:47 +08:00
2026-07-11 15:58:07 +08:00
2026-07-11 15:58:07 +08:00
2026-07-04 13:54:04 +08:00
2026-03-25 16:28:33 +08:00
2026-07-11 15:58:07 +08:00
2026-07-07 21:44:28 +08:00
2026-07-07 21:44:28 +08:00
2026-05-03 23:40:59 +08:00
2026-07-04 23:09:29 +08:00
2026-07-04 13:54:04 +08:00
2026-05-07 08:34:43 +08:00
2026-07-14 09:55:38 +08:00
2026-06-18 10:09:46 +08:00
2026-07-08 21:58:33 +08:00
2026-07-13 18:38:32 +08:00
2026-07-13 19:33:40 +08:00
2026-03-30 16:02:23 +08:00
2026-06-12 15:24:58 +08:00
2026-07-12 23:04:59 +08:00
2026-07-11 22:46:10 +08:00
2026-06-14 10:30:45 +08:00
2026-06-08 23:17:22 +08:00
2026-07-14 08:14:21 +08:00
2026-07-13 10:40:22 +08:00
2026-07-13 19:26:07 +08:00
2026-04-23 23:59:47 +08:00
2026-05-02 06:37:49 +08:00
2026-07-11 15:41:57 +08:00
2026-07-11 15:41:57 +08:00
2026-07-13 19:26:07 +08:00
2026-06-19 21:42:42 +08:00
2026-07-08 17:10:27 +08:00
2026-07-14 21:51:47 +08:00
2026-07-07 19:55:33 +08:00
2026-07-01 22:30:55 +08:00
2026-06-24 07:28:17 +08:00
2026-07-11 15:41:57 +08:00
2026-05-21 21:18:10 +08:00
2026-06-18 10:15:31 +08:00
2026-07-11 15:53:14 +08:00
2026-07-10 22:13:50 +08:00
2026-06-21 21:43:43 +08:00
2026-07-14 10:43:13 +08:00
2026-06-12 15:24:58 +08:00
2026-07-14 21:37:47 +08:00
2026-07-04 09:21:19 +08:00
2026-06-02 22:43:22 +08:00
2026-07-03 08:49:33 +08:00
2026-05-22 21:42:14 +08:00
2026-07-14 21:37:47 +08:00
2026-07-08 14:41:16 +08:00
2026-06-10 23:26:15 +08:00
2026-03-14 22:55:52 +08:00
2026-07-11 23:15:03 +08:00
2026-06-12 22:48:47 +08:00
2026-07-08 22:26:06 +08:00
2026-07-04 23:14:46 +08:00
2026-05-10 22:00:57 +08:00
2026-06-23 23:37:41 +08:00
2026-03-26 14:20:18 +08:00
2026-05-10 23:09:03 +08:00
2026-05-19 22:11:46 +08:00
2026-07-11 08:29:42 +08:00
2026-07-04 11:27:19 +08:00
2026-07-10 08:07:25 +08:00
2026-04-06 15:09:57 +08:00
2026-07-06 20:57:41 +08:00
2026-07-06 20:57:41 +08:00
2026-07-12 11:24:24 +08:00
2026-07-14 09:49:43 +08:00
2026-07-03 08:01:46 +08:00
2026-07-03 08:01:46 +08:00
2026-07-14 08:58:06 +08:00
2026-07-14 08:58:06 +08:00
2026-07-03 08:01:46 +08:00
2026-07-03 08:49:33 +08:00
2026-06-25 20:10:49 +08:00
2026-06-25 20:10:49 +08:00
2026-07-03 08:49:33 +08:00
2026-06-25 20:10:49 +08:00
2026-06-25 20:10:49 +08:00
2026-06-25 20:10:49 +08:00
2026-06-25 20:10:49 +08:00
2026-06-25 20:10:49 +08:00
2026-06-25 20:10:49 +08:00
2026-06-25 20:10:49 +08:00
2026-06-25 20:10:49 +08:00
2026-06-25 20:10:49 +08:00
2026-06-25 20:10:49 +08:00
2026-07-12 12:13:02 +08:00
2026-05-12 23:18:54 +08:00
2026-07-04 22:56:24 +08:00
2026-07-01 16:43:56 +08:00
2026-07-14 10:43:13 +08:00
2026-07-04 21:31:01 +08:00
2026-04-26 15:09:25 +08:00
2026-07-04 13:54:04 +08:00
2026-07-11 09:18:12 +08:00
2026-07-14 10:43:13 +08:00
2026-05-02 15:16:16 +08:00
2026-06-09 15:29:40 +08:00
2026-06-08 22:04:38 +08:00
2026-04-28 11:13:17 +08:00
2026-04-06 15:18:34 +08:00
2026-07-04 09:21:19 +08:00
2026-07-06 07:21:12 +08:00
2026-07-04 21:35:05 +08:00
2026-07-12 07:52:45 +08:00
2026-07-05 00:07:27 +08:00
2026-07-12 11:51:31 +08:00
2026-07-06 22:24:14 +08:00
2026-06-07 17:47:11 +08:00