Skip to content

fix: MCP mutations now reliably notify the UI#67

Merged
jcanizalez merged 2 commits intomainfrom
fix/mcp-db-signal-notification
Mar 19, 2026
Merged

fix: MCP mutations now reliably notify the UI#67
jcanizalez merged 2 commits intomainfrom
fix/mcp-db-signal-notification

Conversation

@jcanizalez
Copy link
Copy Markdown
Owner

Summary

  • Root cause: fs.watch() on the SQLite WAL file was unreliable for detecting external DB writes from the MCP stdio process — SQLite checkpoints could flush the WAL before the watcher fired, causing MCP-created tasks/projects/workflows/workspaces to never appear in the UI
  • Added dbSignalChange() to database.ts — writes a .db-signal file after every MCP mutation as an explicit notification trigger
  • Config manager now watches .db-signal, .db-wal, and .db changes (was only .db-wal), with debounce reduced from 1s → 300ms
  • All 12 mutation points across 4 MCP tool files (tasks, projects, workspaces, workflows) now call dbSignalChange() after writes

Test plan

  • Create a task via MCP (create_task) — verify it appears in the UI within ~300ms
  • Update a task via MCP (update_task) — verify change reflects in UI
  • Delete a task via MCP (delete_task) — verify it disappears from UI
  • Repeat for projects, workspaces, and workflows
  • Verify tasks created via the UI still work (no regression)
  • Test on macOS and verify fs.watch picks up the .db-signal file

The WAL file watcher was unreliable for detecting external DB writes from
the MCP stdio process — SQLite checkpoints could flush the WAL before
fs.watch fired, causing tasks/projects/workflows/workspaces created via
MCP to never appear in the UI.

Added dbSignalChange() which writes a .db-signal file after every MCP
mutation. The config-manager now watches for .db-signal, .db-wal, and .db
changes (was only .db-wal). Debounce reduced from 1s to 300ms.
Copilot AI review requested due to automatic review settings March 19, 2026 17:08
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR improves cross-process UI refresh reliability by adding an explicit filesystem “signal” that the main server can watch to detect SQLite mutations performed by the MCP stdio process (avoiding missed events when relying on .db-wal alone).

Changes:

  • Added dbSignalChange() in the server database module to “touch” a .db-signal file after MCP-driven mutations.
  • Updated ConfigManager.watchDb() to watch .db-signal, .db-wal, and .db with a reduced debounce (1s → 300ms).
  • Updated MCP tool mutation handlers (tasks/projects/workspaces/workflows) to call dbSignalChange() after DB writes.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
packages/server/src/database.ts Adds dbSignalChange() that writes/updates .db-signal in the config/db directory.
packages/server/src/config-manager.ts Expands DB watcher to include .db-signal/.db and reduces debounce to improve UI update latency.
packages/mcp/src/tools/workspaces.ts Calls dbSignalChange() after create/update/delete workspace mutations.
packages/mcp/src/tools/workflows.ts Calls dbSignalChange() after create/update/delete workflow mutations.
packages/mcp/src/tools/tasks.ts Calls dbSignalChange() after create/update/delete task mutations.
packages/mcp/src/tools/projects.ts Calls dbSignalChange() after create/update/delete project mutations.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +84 to +93
const WATCH_SUFFIXES = ['.db-signal', '.db-wal', '.db']

try {
this.dbWatcher = fs.watch(DB_DIR, (eventType, filename) => {
if (!filename || !filename.endsWith('.db-wal')) return
if (!filename || !WATCH_SUFFIXES.some((s) => filename.endsWith(s))) return
// Debounce -- multiple writes can fire rapidly
if (this.debounceTimer) clearTimeout(this.debounceTimer)
this.debounceTimer = setTimeout(() => {
this.notifyChanged()
}, 1000)
}, 300)
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Added tests in e3ced90 — covers all three suffix triggers (.db-signal, .db-wal, .db), unrelated file filtering, and debounce coalescing of rapid events into a single notification.

Cover the new watchDb behavior: .db-signal, .db-wal, and .db file
detection, unrelated file filtering, and 300ms debounce coalescing.
@jcanizalez jcanizalez merged commit 87ba96f into main Mar 19, 2026
1 check passed
@jcanizalez jcanizalez deleted the fix/mcp-db-signal-notification branch March 19, 2026 18:34
This was referenced Mar 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants