Skip to content

feat: MCP channel notifications + image path/URL support#15

Open
xzneozx96 wants to merge 3 commits into199-biotechnologies:mainfrom
xzneozx96:feat/mcp-channel-notifications
Open

feat: MCP channel notifications + image path/URL support#15
xzneozx96 wants to merge 3 commits into199-biotechnologies:mainfrom
xzneozx96:feat/mcp-channel-notifications

Conversation

@xzneozx96
Copy link
Copy Markdown

@xzneozx96 xzneozx96 commented Apr 5, 2026

Summary

  • MCP channel notifications: The MCP server connects to the daemon's SSE stream (GET /api/events) and forwards every inbound WhatsApp message to Claude Code as a notifications/claude/channel notification — incoming messages arrive in the session automatically without polling. Includes auto-reconnect with exponential backoff.
  • Image tool path/URL support: whatsrust_image MCP tool now accepts a path parameter (local file path or https:// URL) in addition to inline base64 data. The daemon's handle_media endpoint was also updated to support URL fetching directly.

Changes

File What changed
src/mcp.rs SSE forwarder thread, channel notification dispatch, path/URL support in whatsrust_image handler
src/api.rs handle_media accepts https:// URLs — fetches with ureq, detects MIME from Content-Type
Cargo.toml Added ureq = "3" as explicit dependency
README.md Documented channel notification setup and image tool path parameter

Test plan

  • Start daemon, open Claude Code session — verify inbound WhatsApp messages appear as channel notifications
  • Call whatsrust_image with a local file path — verify image sends
  • Call whatsrust_image with an https:// URL — verify image fetches and sends
  • Call whatsrust_image with inline data (existing behaviour) — verify no regression
  • Kill daemon, verify MCP server reconnects when daemon restarts

… as channel notifications

Implements the MCP channel contract so incoming WhatsApp messages are pushed
into the Claude Code session automatically via notifications/claude/channel.

Changes:
- Declare claude/channel experimental capability in initialize response
- Add server instructions telling Claude how to handle inbound messages
- Spawn a writer thread that owns stdout for immediate async writes
- Spawn SSE forwarder thread that connects to /api/events on the daemon,
  parses inbound events, and pushes notifications/claude/channel with
  chat_jid, sender, message_id, timestamp, is_from_me, chat_type as meta
- Auto-reconnects with exponential backoff on daemon restart

README: add Claude Code ~/.claude.json config snippet and systemd user
service setup for persistent daemon auto-start on boot.
- mcp.rs: whatsrust_image now accepts 'path' (file or URL) in addition
  to inline base64 'data'; resolves to base64 before forwarding to API
- api.rs: /api/image (and all media endpoints) handle https:// paths
  by fetching the URL via ureq; local-path mode unchanged (loopback-only)
- Cargo.toml: add ureq = '3' as direct dependency
@xzneozx96 xzneozx96 changed the title feat: Claude Code channel support — forward inbound WhatsApp messages as channel notifications feat: MCP channel notifications + image path/URL support Apr 5, 2026
- clamp() instead of .max().min() chains (api.rs)
- next_back() for DoubleEndedIterator::last (api.rs)
- Default impl for BridgeMetrics (bridge.rs)
- Entry API instead of contains_key + insert (bridge.rs)
- #[allow] for borrowed_box on BoundedMsgCache::get (bridge.rs)
- #[allow(clippy::too_many_arguments)] on send_message_with_preview and handle_outbound (bridge.rs)
- Remove needless borrows on get_client_handle calls (bridge.rs)
- Remove needless borrow on serde_json::to_value(status) (bridge.rs)
- is_empty() companion for AtomicDedupCache::len (dedup.rs)
- strip_prefix() instead of manual index slicing (mcp.rs)
- #[allow(dead_code)] on extract_image_dimensions (media_utils.rs)
- #[allow(clippy::should_implement_trait)] on from_str (outbound.rs)
- Collapsible str::replace with char array (outbound.rs)
- div_ceil() instead of manual ceil formula (qr.rs)
- is_some_and() instead of map_or(false, ...) (storage.rs)
- .copied() instead of .map(|s| *s) (main.rs)

New tests (mcp.rs): 15 unit tests covering extract_display_text for all
content kinds, build_channel_notification metadata and chat_type, and
mcp_connect_host wildcard/specific address handling.
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