AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
MCP verified MIT Self-run

Session Bridge Mcp

mcp-c2developers-session-bridge-mcp · by c2developers

MCP server that lets multiple Claude Code sessions talk to each other over tmux (gestor/dev/reviewer workflow)

No reviews yet
0 installs
5 views
0.0% view→install

Install

$ agentstack add mcp-c2developers-session-bridge-mcp

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/mcp-c2developers-session-bridge-mcp)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
2mo ago

Declared compatibility

Claude CodeClaude DesktopCursorWindsurf

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Session Bridge Mcp? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

🌉 session-bridge-mcp

Let multiple Claude Code sessions talk to each other.

One session writes straight into another's prompt over tmux, and every message lands in a shared conversation log any session can review.

[](https://modelcontextprotocol.io) [](https://bun.sh) [](https://github.com/tmux/tmux) [](#license)


Why

You run one Claude Code session to write code and another to review the PR — and you keep playing carrier pigeon between them. session-bridge removes the pigeon. Each session lives in its own tmux pane under a role, and they message each other directly.

The canonical setup is a 3-session loop:

        ┌─────────────────────────────────────────────────────────┐
        │   gestor   ·  talks to you, orchestrates the workflow     │
        └───────────────┬─────────────────────────┬────────────────┘
                  send   │                         │   send
                         ▼                         ▼
                 ┌──────────────┐          ┌──────────────────┐
                 │     dev      │ ───────▶ │     reviewer     │
                 │ writes code  │   send   │  reviews the PR  │
                 └──────────────┘ ◀─────── └──────────────────┘
                                    send

> gestor = manager. Rename the roles to whatever you like — they are just > strings.


How it works

Two transports, on purpose:

| Transport | What | Needs polling? | |---|---|---| | PUSH | send injects text into the peer's tmux pane (set-buffer → bracketed-paste → Enter). The peer receives it as a brand-new user turn. Claude Code even queues it if the peer is mid-task. | No — it's pushed. | | PULL | read_peer captures what's currently on a peer's screen. Used to watch a session (e.g. the manager noticing the dev is asking the user something). | Yes — pair with the native /loop skill. |

Every message is also logged twice, so nothing is lost and any session can catch up:

  • conversation.jsonl — the single ordered cross-session thread.
  • mailbox/.jsonl — a per-role inbox (audit + fallback).

Bracketed paste (paste-buffer -p) means multi-line messages, quotes and whitespace survive intact — the TUI won't treat embedded newlines as submits.

State lives under ~/.claude/session-bridge/, so it is shared across every Claude Code session on the machine and survives /clear.

~/.claude/session-bridge/
├── registry.json          # role → tmux pane mapping
├── prompts.json           # role → persistent system prompt (restored on /clear)
├── conversation.jsonl      # global ordered thread
└── mailbox/
    ├── gestor.jsonl
    ├── dev.jsonl
    └── reviewer.jsonl

Install

Requires Bun and tmux, and Claude Code launched inside a tmux pane.

git clone git@github.com:c2developers/session-bridge-mcp.git
cd session-bridge-mcp
bun install

Register the server with Claude Code at user scope (available in every project):

claude mcp add session-bridge -s user -- bun /abs/path/to/session-bridge-mcp/src/index.ts

Or drop it into a project's .mcp.json (see .mcp.example.json):

{
  "mcpServers": {
    "session-bridge": {
      "command": "bun",
      "args": ["/abs/path/to/session-bridge-mcp/src/index.ts"]
    }
  }
}

Configure the state directory with SESSION_BRIDGE_DIR if you don't want the default ~/.claude/session-bridge/.


Quickstart — 3 sessions in 60 seconds

# Three tmux sessions, each will run its own Claude Code
tmux new-session -d -s gestor
tmux new-session -d -s dev
tmux new-session -d -s reviewer

# In each one, launch `claude` and give it its role as the first message:
#   gestor   → "registra esta sesión como 'gestor' con session-bridge"
#   dev      → "registra esta sesión como 'dev' con session-bridge"
#   reviewer → "registra esta sesión como 'reviewer' con session-bridge"

Each session calls register(role) once — it auto-detects its own pane from $TMUX_PANE. After that they can reach each other by role name.

> Bootstrap trick: an already-registered session can register the others for > you by injecting the instruction into their panes (the manager does exactly > this). It just needs their pane ids from tmux list-panes -a.


Tools

| Tool | Signature | Purpose | |---|---|---| | register | (role, pane?) | Register the current session under a role. Auto-detects the tmux pane from $TMUX_PANE; pass pane to override. Call once per session. | | list_peers | () | All registered roles, their panes, cwd and last-seen time. | | send | (to, from, text, submit?, tag?) | Push a message into a peer's prompt. submit=false types it without sending; tag=false drops the [from:…] prefix. Also logs to the thread + mailbox. | | read_peer | (role, lines?) | Capture the peer's visible screen (default 50 lines of scrollback). | | detect_question | (role, lines?) | Classify the peer's screen — busy / waiting_select / waiting_text / idle / unknown — and parse any open menu's options + heading. Lets the manager notice when a peer needs an answer. | | respond | (role, keys) | Send raw control keys to drive an interactive menu/permission prompt, e.g. ['1'], ['Down','Down','Enter'], ['Escape']. For prose, use send. | | history | (limit?, role?) | Read the shared conversation, newest last. Filter by a role involved. | | inbox | (role, limit?) | Read a role's mailbox — a poll/fallback if a pushed message was missed. | | set_prompt | (role, prompt) | Save a persistent "system prompt" / briefing for a role. Survives /clear and restarts; auto-reinjected by the SessionStart hook. | | get_prompt | (role) | Read back a role's saved prompt ({found:false} if none). | | list_prompts | () | All saved role prompts. | | delete_prompt | (role) | Forget a role's saved prompt so it stops being reinjected. |

The watch loop (PULL) — answering a peer's questions

Receiving messages is push, so no loop is needed for that. A loop is only for watching a peer's screen and noticing when it's stuck on a question (plan-mode approval, a clarifying menu, a permission prompt). detect_question classifies the screen so the loop doesn't bother a busy peer; respond then drives the menu.

With Claude Code's native /loop skill, run this in the manager:

/loop 30s para 'dev' y 'reviewer' llama detect_question. Si state=='waiting_select'
o 'waiting_text', enséñame la pregunta y las opciones y decide la respuesta según el
flujo: contéstala con respond(role, keys) para menús (p.ej. ['1','Enter']) o con
send(...) para texto. Si la decisión es del usuario, párate y pregúntame. Si state
=='busy' o 'idle', no hagas nada.

> Menus vs prose. A menu/permission prompt is not a text turn — typing > into it does nothing useful. Use respond with key tokens for those, and > send only when the peer is genuinely waiting for free text.

Sending slash commands across sessions

Slash commands are just text injected into the prompt:

send(to:'dev', from:'gestor', text:'/clear')

Persistent role prompts — surviving /clear

/clear wipes a session's context — including who it is and how it should behave. Re-typing each role's briefing every time is the pigeon problem all over again. So a role's "system prompt" can be saved once and restored automatically.

  1. Save a briefing per role (usually the gestor sets them up):

`` set_prompt(role:'dev', prompt:'You are the dev. Work on the assigned issue, keep commits small, open a PR and ping the reviewer. Never merge yourself.') ``

It's written to prompts.json and survives /clear, restarts and reboots.

  1. Restore happens on its own. A SessionStart hook fires on /clear (and

on startup/resume), reads the session's $TMUX_PANE, reverse-looks-up its role in registry.json, and reinjects that role's saved prompt as additionalContext. The session wakes up already knowing its identity — no re-typing, no manual get_prompt.

Wire the hook once in ~/.claude/settings.json (user scope, so it fires in every session regardless of project):

{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "clear|startup|resume",
        "hooks": [
          {
            "type": "command",
            "command": "/abs/path/to/bun run /abs/path/to/session-bridge-mcp/src/session-start-hook.ts",
            "timeout": 15
          }
        ]
      }
    ]
  }
}

The hook is a silent no-op when it can't help: outside tmux, on an unregistered pane, or when no prompt is saved for the role — so it never blocks a session from starting. If a pane is bound to several roles (e.g. dev and developer), the most recently registered role wins.

> The prompt is restored as context, not as a literal model system prompt — > Claude Code has no API to overwrite its own system prompt mid-session. In > practice an injected role briefing at session start behaves the same way.


Full workflow example

  1. You → gestor: "implement issue #14".
  2. gestor → dev: send(to:'dev', from:'gestor', text:'Take issue #14: . Branch /14-slug. Ping the reviewer with the PR URL when ready.')
  3. dev codes. If it needs a user decision, the gestor (watching via /loop + read_peer('dev')) sees it and answers — or escalates to you.
  4. dev → reviewer: send(to:'reviewer', from:'dev', text:'PR #21 ready: . Please review.')
  5. reviewer reviews → send(to:'dev', …) with changes, or send(to:'gestor', …) with "approved".
  6. dev fixes → back to step 4. reviewer confirms → merges, closes issue/PR.
  7. reviewer → gestor: "merged & closed". The gestor sends /clear to dev and kicks off the next task.

Troubleshooting

| Symptom | Fix | |---|---| | register fails: $TMUX_PANE is unset | You launched Claude Code outside tmux. Start it inside tmux, or pass pane (tmux display-message -p '#{pane_id}'). | | Message logged but delivered:false | The target pane died. Re-register that session (pane ids change when tmux restarts). The message is still in the mailbox. | | Peer didn't react to a pushed message | It was busy; Claude Code queues it. Or check its inbox(role). | | MCP added mid-session but tools missing | Restart Claude Code — user-scope servers load at startup. | | Prompt not restored after /clear | The session must have been registered in that pane and have a saved prompt (get_prompt(role)). The hook only fires if wired in settings.json; check it with /hooks or run the script manually piping {"source":"clear"} with TMUX_PANE set. |


Security

send injects text into another Claude Code prompt and read_peer reads its screen. Anyone who can write to ~/.claude/session-bridge/registry.json, or drive your tmux server, can inject prompts into your sessions. Run this only on a trusted local machine. There is no network listener — all coordination is local files + the local tmux socket.


License

MIT © c2developers

Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.