Skip to content

fix: skip unchanged MCP tool writes to Postgres - #2796

Open
supreme-gg-gg wants to merge 4 commits into
kagent-dev:release/v0.10.xfrom
supreme-gg-gg:feat/remotemcpserver-refresh
Open

fix: skip unchanged MCP tool writes to Postgres#2796
supreme-gg-gg wants to merge 4 commits into
kagent-dev:release/v0.10.xfrom
supreme-gg-gg:feat/remotemcpserver-refresh

Conversation

@supreme-gg-gg

Copy link
Copy Markdown
Contributor

Summary

  • Cache the last persisted MCP tool list "snapshot" in the reconciler and skip StoreToolServer / RefreshToolsForServer when nothing changed.
  • Controllers still poll on the existing refresh interval (which is still configurable through feat: configurable refresh interval for tool server controllers #2480), but idle Postgres is no longer written every cycle.

Test plan

  • Unit tests for snapshot equality, description/tool changes, and cache evict
  • On a cluster: confirm periodic successfully registered remote MCP server logs, and that tool / toolserver.updated_at and n_tup_upd stay at the first write

@supreme-gg-gg
supreme-gg-gg requested a review from a team as a code owner September 10, 2026 17:27
Copilot AI lite review requested due to automatic review settings September 10, 2026 17:27
@github-actions github-actions Bot added the bug Something isn't working label Sep 10, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new skip/write logic introduces a couple of correctness risks (notably around initial DB visibility on discovery failure and snapshot determinism) that should be addressed before merging.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR reduces unnecessary Postgres churn from MCP tool discovery by caching the last persisted tool list “snapshot” in the controller reconciler and skipping StoreToolServer / RefreshToolsForServer when the discovered tool set and description are unchanged across polling cycles.

Changes:

  • Added an in-memory per-(server, groupKind) tool snapshot cache to avoid repeated no-op writes during periodic tool discovery.
  • Evicted cached snapshots when ToolServer resources are deleted.
  • Added unit tests covering snapshot equality, change detection, and cache eviction.
File summaries
File Description
go/core/internal/controller/reconciler/reconciler.go Adds snapshot caching + eviction to skip unchanged Postgres writes during MCP tool polling.
go/core/internal/controller/reconciler/reconciler_test.go Adds unit tests for snapshot determinism, change detection, and cache eviction behavior.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread go/core/internal/controller/reconciler/reconciler.go
Comment thread go/core/internal/controller/reconciler/reconciler.go

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Snapshot hashing currently ignores json.Marshal errors (risking incorrect “unchanged” detection) and there are unresolved cache/DB-healing edge cases that should be addressed or explicitly accepted.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (2)

Previously missed (2) — in code that hasn't changed since the last review.

go/core/internal/controller/reconciler/reconciler.go:1181

  • The early-return cache is purely in-memory. If the ToolServer/tools rows are deleted or the DB is reset while this controller process keeps running, subsequent reconciles will keep skipping the StoreToolServer/RefreshToolsForServer writes until the tool list changes (or the controller restarts), leaving DB-backed APIs empty/stale. Consider adding a TTL-based forced refresh (e.g., re-write at least once per N intervals) or validating row existence before skipping writes.
    go/core/internal/controller/reconciler/reconciler.go:1211
  • json.Marshal errors are currently ignored when computing the snapshot. If marshaling ever fails (e.g., a future field type becomes non-marshalable), b becomes nil and the hash degenerates to a constant, which can incorrectly treat different tool lists as "unchanged" and skip required DB updates. Handle the error with a deterministic fallback that still depends on the tool data.
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread go/core/internal/controller/reconciler/reconciler.go
@supreme-gg-gg
supreme-gg-gg requested a lite review from Copilot September 10, 2026 19:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@EItanya EItanya left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 AI-generated review.

  1. Invalidate the cached snapshot before attempting changed writesreconciler.go:1184–1189. StoreToolServer commits separately from the tool refresh. If snapshot A is cached, writing B updates the server row, and the refresh fails, A remains cached. Rolling back to A then skips persistence indefinitely, leaving B’s metadata in the database. An uncertain commit outcome can also leave stale tools. Evict the snapshot before attempting the writes; remember it only after both succeed.

Reproduced through real MCP discovery with injected database failures. Existing reconciler tests pass; both regression cases and the full package pass with the one-line fix applied through a scratch overlay. No live PostgreSQL testing was performed.

Signed-off-by: Jet Chiang <pokyuen.jetchiang-ext@solo.io>
Keep failed MCP servers visible in the toolserver API without repeating the write, and make duplicate tool names hash deterministically.

Signed-off-by: Jet Chiang <pokyuen.jetchiang-ext@solo.io>
Signed-off-by: Jet Chiang <pokyuen.jetchiang-ext@solo.io>
Signed-off-by: Jet Chiang <pokyuen.jetchiang-ext@solo.io>
@supreme-gg-gg
supreme-gg-gg force-pushed the feat/remotemcpserver-refresh branch from f423a4d to 1f470b9 Compare September 11, 2026 03:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants