
Security News
GPT-6 Astra Attempts Supply Chain Attacks Against Open Source Maintainers in Testing
GPT-6 Astra hits 100% on ExploitBench and finds zero-days autonomously, while independent tests reveal scope violations and monitoring gaps.
claude-intercom
Advanced tools
Two-way communication bridge between Claude Code sessions using the Channels API
Two-way communication bridge between Claude Code sessions using the Channels API.
Let two Claude Code instances on different machines talk to each other in real-time. One sends a message, the other receives it instantly as a channel notification and can reply back.
On 7 August 2026, Claude Code v2.1.224 shipped cross-session messaging — ListAgents and SendMessage, built in, nothing to install.
If you are on macOS or Linux and you want your own sessions to talk to each other, use the native feature. It is better than this project in every way that matters: no setup, no shared secret, no open port, permission-aware delivery, and same-machine messages never leave your machine. This README is not going to pretend otherwise.
Intercom was built in March 2026, five months before that landed. What follows is an honest account of what each one covers.
| Your own sessions, same machine | Yes — over a per-session socket, never through Anthropic servers |
| Your own sessions, your other machines | Yes — requires Remote Control on both ends; messages travel through Anthropic servers. Starting a conversation needs v2.1.225+ |
| Your Claude Code on the web sessions | Yes — through Anthropic servers |
| Subagents and agent teams | Yes — same SendMessage tool |
These are the cases where Intercom is still the answer:
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC, DISABLE_TELEMETRY, DO_NOT_TRACK, or DISABLE_GROWTHBOOK turn it off.Your own sessions, macOS/Linux -> native cross-session messaging
Two different developers -> Intercom
Native Windows -> Intercom
Bedrock / Vertex / Foundry -> Intercom
Must not transit Anthropic servers -> Intercom
One more difference worth knowing: native messaging is plain text between Claudes and applies the receiving session's own permission rules and inbound controls. Intercom is a raw pipe with a shared secret — anyone holding your secret and address can push text straight into your session. Read Security before you expose a port.
If you have a backend developer and a frontend developer each running Claude Code on separate machines, they currently have to relay questions through Slack/Discord/copy-paste. Claude Intercom creates a direct hotline between the two AI sessions — one Claude can ask the other about endpoints, schemas, or implementation details and get answers from the actual codebase.
Machine A Machine B
(e.g. backend dev) (e.g. frontend dev)
Claude Code A Claude Code B
| |
+-- intercom.ts ---HTTP POST----> intercom.ts --+
| (channel) <--HTTP POST-- (channel) |
| |
+-- stdio (MCP) --+ +-- stdio (MCP) -----+
| |
Claude A Claude B
Both instances run the same intercom.ts file. Each listens for HTTP messages and pushes them into its local Claude Code session via the Channels API. Each also exposes send_message and check_message tools that Claude can call.
On both machines:
git clone https://github.com/MuhammadTalhaMT/claude-intercom.git
cd claude-intercom
bun install
Copy the example config into your project's .mcp.json:
Machine A (e.g. backend — static IP or VPS):
{
"mcpServers": {
"intercom": {
"command": "bun",
"args": ["/path/to/claude-intercom/intercom.ts"],
"env": {
"MY_ROLE": "backend",
"REMOTE_HOST": "MACHINE_B_IP:8788",
"INTERCOM_SECRET": "your-shared-secret",
"INTERCOM_PORT": "8788"
}
}
}
}
Machine B (e.g. frontend — can be behind NAT):
{
"mcpServers": {
"intercom": {
"command": "bun",
"args": ["/path/to/claude-intercom/intercom.ts"],
"env": {
"MY_ROLE": "frontend",
"REMOTE_HOST": "MACHINE_A_IP:8788",
"INTERCOM_SECRET": "your-shared-secret",
"INTERCOM_PORT": "8788"
}
}
}
}
On both machines:
claude --dangerously-load-development-channels server:intercom
In either Claude Code session:
"Send a message to the other developer asking what API endpoints are available for the dashboard."
Claude will use the send_message tool to POST the message to the other machine. The other Claude receives it as a channel notification and responds.
Use Tailscale. Install it on both machines and they get stable private addresses on your own tailnet. Then point each side at the other's tailnet address:
"REMOTE_HOST": "other-machine:8788"
This is strictly better than exposing a port to the internet: no public listener, no port forwarding, the address doesn't change when your ISP reassigns your IP, and device identity is enforced by Tailscale rather than resting entirely on a shared string. Set hostname to 127.0.0.1 in Bun.serve if you want to be certain nothing outside the tailnet can reach it at all.
If you can't use Tailscale, ngrok still works:
# On the machine behind NAT
ngrok http 8788
"REMOTE_HOST": "your-subdomain.ngrok-free.app"
The intercom auto-detects ngrok URLs and switches to HTTPS. Note this does put a publicly reachable endpoint in front of your Claude session, gated only by the shared secret — pick a strong one.
send_messageSends a message and returns immediately with an id. It does not wait for an answer — the reply arrives later as its own inbound message.
| Argument | Required | Description |
|---|---|---|
message | Yes | The text to send |
replyTo | No | The id of the incoming message this answers, so the sender can correlate it |
expectReplyWithin | No | How long a reply should reasonably take: "30s", "5m", "2h" |
The acknowledgement deliberately does not claim the other developer received it. An HTTP 200 proves the remote process accepted the message, not that the other Claude ever read it.
check_messageAnswers the question a fire-and-forget channel otherwise can't: is this reply slow, or is it never coming? Pass an id, or omit it to list everything outstanding.
Every message sits in one of three states:
| State | Meaning |
|---|---|
sent | We tried, but the remote process never acked it. The other machine is probably unreachable |
delivered-to-process | Their intercom took it. Their Claude may or may not have read it — that session could be idle, closed, or out of usage |
answered | A reply came back carrying replyTo for this id |
expectReplyWithin is what makes "overdue" mean anything, and it's per message rather than one global timeout — so a quick endpoint lookup and a long investigation aren't judged on the same clock.
| Environment Variable | Required | Default | Description |
|---|---|---|---|
MY_ROLE | Yes | developer-a | Label for this instance (appears in message tags) |
REMOTE_HOST | Yes | localhost:8789 | Address of the other machine (host:port or tunnel URL) |
INTERCOM_SECRET | Yes | change-me-in-production | Shared secret — must match on both sides |
INTERCOM_PORT | No | 8788 | Port to listen on for incoming messages |
INTERCOM_SEND_TIMEOUT_MS | No | 10000 | How long an outbound POST may hang before giving up |
intercom.ts as a subprocess (MCP server over stdio)claude/channel capability — this registers it as a Channelmcp.notification() with method: 'notifications/claude/channel'<channel> tag, carrying the message idsend_message with replyTo set to that id, which POSTs to the remote machinereplyTo against its own outbound record and marks that message answeredThe stdio leg is not an implementation detail you can swap for HTTP. It is what attaches the server to a specific live Claude Code session — the claude/channel capability is registered over that connection, and it's the reason mcp.notification() lands in a conversation at all. Host this remotely and the notification goes to whatever MCP client connected instead.
X-Intercom-Secret header matching the configured secret. Requests without it get a 401 Unauthorized.0.0.0.0 for cross-machine access. Set to 127.0.0.1 if using a tunnel.Warning: Those instructions are a default, not a boundary. You cannot fix prompt injection with prompt instructions — anyone holding your secret and address can put text into your Claude session, and the only real limits are that session's own permission prompts. Native cross-session messaging enforces this properly with hold/accept/refuse inbound controls; this does not. Use a strong secret, keep it off the public internet, and don't pair with a peer you wouldn't hand a terminal to.
| Method | Path | Auth | Description |
|---|---|---|---|
GET | /health | No | Returns {"status":"ok","role":"...","version":"..."} |
POST | /message | X-Intercom-Secret header | Pushes message into Claude's session |
POST /message body:
{
"id": "8649f5da",
"replyTo": "40b0fd17",
"content": "3 routes, all behind requireTenant()",
"role": "backend-dev",
"timestamp": "2026-08-16T09:41:00.000Z"
}
id and replyTo are optional — a message without them still delivers, it just can't be correlated.
MIT
FAQs
Two-way communication bridge between Claude Code sessions using the Channels API
The npm package claude-intercom receives a total of 52 weekly downloads. As such, claude-intercom popularity was classified as not popular.
We found that claude-intercom demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
GPT-6 Astra hits 100% on ExploitBench and finds zero-days autonomously, while independent tests reveal scope violations and monitoring gaps.

Product
Socket can now send alerts and supply chain attack notifications to Microsoft Teams, with filters that route the right updates to each channel.

Security News
pnpm 12 rewrites the package manager in Rust, cutting install times by up to 90% while preserving pnpm 11 workflows and lockfiles.