Skip to content

Implement resource subscriptions with file sync (resources-subscribe)#273

Draft
jancurn wants to merge 1 commit into
mainfrom
claude/focused-maxwell-br7onb
Draft

Implement resource subscriptions with file sync (resources-subscribe)#273
jancurn wants to merge 1 commit into
mainfrom
claude/focused-maxwell-br7onb

Conversation

@jancurn

@jancurn jancurn commented Jun 13, 2026

Copy link
Copy Markdown
Member

Summary

Implements the resources-subscribe and resources-unsubscribe commands, allowing users to keep local files in sync with MCP server resources. When a resource is subscribed, the bridge downloads it to a local file and automatically re-syncs whenever the server sends notifications/resources/updated notifications. Subscriptions persist across bridge restarts.

Key Changes

Core Resource Sync Infrastructure:

  • Added ResourceSyncManager (src/bridge/resource-sync.ts) to track subscriptions and coordinate file syncing
    • Handles initial download on subscribe, re-syncing on server notifications
    • Coalesces burst notifications into at most one follow-up sync
    • Records per-subscription errors and sync timestamps
    • Persists subscriptions to sessions.json for crash recovery
  • Added selectResourceContent() and writeResourceFile() helpers (src/lib/resource-content.ts) for materializing MCP resource contents
    • Selects appropriate content item from multi-item responses
    • Decodes text and base64 blob payloads to bytes
    • Writes atomically (temp file + rename) with parent directory creation

CLI Commands:

  • Implemented resources-subscribe <uri> <file> command to subscribe and sync a resource to a local file
  • Implemented resources-unsubscribe <uri> command to remove subscriptions (keeps the synced file)
  • Enhanced resources-read command with:
    • -o/--output <file> flag to save resource content to a file (binary-safe)
    • --raw flag to print bare content suitable for piping
    • Proper handling of binary (blob) content — summarized in human mode, never dumped

Bridge Integration:

  • Wired ResourceSyncManager into bridge process to handle notifications/resources/updated
  • Added restoreResourceSubscriptions() to re-establish persisted subscriptions on bridge startup
  • Subscriptions survive bridge restarts and session reconnections

Session Data & Output:

  • Added resourceSubscriptions field to SessionData for persistence
  • Added ResourceSubscriptionEntry type with URI, file path, timestamps, and error tracking
  • Enhanced formatServerDetails() to show active subscriptions with sync status
  • Added formatResourceContents() for pretty-printing resource read results
  • Added formatTimeAgo() helper for human-friendly timestamp display

Test Coverage:

  • Comprehensive unit tests for ResourceSyncManager (coalescing, error handling, persistence)
  • Unit tests for resource content selection and file writing
  • E2E test suite (resource-sync.test.sh) covering subscribe/unsubscribe, notifications, restarts, and error cases
  • Test server enhancements: mutable counter resource, binary resource, subscription tracking, and control endpoints

Notable Implementation Details

  • Notification Coalescing: Multiple resources/updated notifications arriving during an in-flight sync are collapsed into exactly one queued follow-up sync, preventing thrashing on rapid updates
  • Error Resilience: Sync failures are recorded per subscription without blocking other operations; the file retains its last good content
  • Atomic Writes: Resource files are written atomically (temp file + rename) to prevent corruption
  • Backward Compatibility: Sessions without subscriptions work unchanged; the resourceSubscriptions field is optional in SessionData

https://claude.ai/code/session_01HWY3cK2NAURyyQRxDDjoBY

…safe

resources-subscribe <uri> <file> now keeps a local file in sync with the
resource: the bridge downloads it on subscribe and rewrites it on every
notifications/resources/updated (re-reading the resource, per the MCP spec
the notification carries no content). Subscriptions persist in
sessions.json, are re-established and re-synced on bridge restart, and are
listed in `mcpc @session` output. resources-unsubscribe stops the sync and
keeps the file.

resources-read gains -o <file> (binary-safe save that decodes base64
blobs; previously advertised but unimplemented) and --raw for piping
(consistent with skills-get --raw, with a TTY guard for binary content).
The default human view renders text in a fenced block and summarizes
binary content instead of dumping it. The never-enforced --max-size
option is removed.

https://claude.ai/code/session_01HWY3cK2NAURyyQRxDDjoBY
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.

3 participants