Skip to content

Add watcher preopen controls and harden server shutdown#120

Open
isham703 wants to merge 1 commit intoisaacphi:mainfrom
isham703:codex/swift-mcp-memory-fix
Open

Add watcher preopen controls and harden server shutdown#120
isham703 wants to merge 1 commit intoisaacphi:mainfrom
isham703:codex/swift-mcp-memory-fix

Conversation

@isham703
Copy link

@isham703 isham703 commented Mar 2, 2026

Summary

This PR addresses Swift MCP memory/process buildup observed in large workspaces by adding opt-in runtime controls and hardening shutdown behavior, while preserving existing defaults.

Changes

  • Add runtime flags/env controls (default-preserving):
    • --watcher-preopen-on-register (default true)
    • --watcher-preopen-max-files (default 0 = unlimited)
    • --idle-timeout (default 0s = disabled)
  • Add watcher config fields:
    • PreopenOnRegistration bool
    • PreopenMaxFiles int
  • Gate registration-time preopen scans behind PreopenOnRegistration.
  • Enforce deterministic preopen cap via PreopenMaxFiles (counts successful opens only).
  • Add idle watchdog and activity tracking using MCP BeforeAny hook.
  • Make server cleanup idempotent (sync.Once) and ensure cleanup always runs when stdio loop exits.
  • Make Client.Close() idempotent in LSP client to avoid repeated wait/close races.
  • Update README with new flags/env and Codex-specific example.

Why

In practice, duplicated MCP stacks plus registration-triggered preopen scans can create high memory pressure and process accumulation. This change gives clients an opt-out/cap for preopen and adds reliable idle/process cleanup.

Compatibility

Defaults preserve current behavior globally, so existing clients are unaffected unless they opt in.

Tests

  • Added/updated unit coverage for:
    • preopen disabled => no registration scan opens
    • preopen enabled => matching files open
    • preopen max cap => bounded opens
    • repeated close calls => idempotent/no-op-safe
  • Ran package tests (non-integration) successfully.

Files

  • main.go
  • internal/watcher/interfaces.go
  • internal/watcher/watcher.go
  • internal/lsp/client.go
  • internal/lsp/client_close_test.go
  • internal/watcher/testing/mock_client.go
  • internal/watcher/testing/watcher_test.go
  • README.md

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.

1 participant