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

Tandem

mcp-maxmedawar-tandem · by Maxmedawar

Tandem is an MCP bridge that lets a chatbot (Claude.ai or ChatGPT) spin up and drive, interactive Claude Code sessions on your own machine. Runs 2 sessions in a lead/worker loop that works autonomously. Also makes claude code respond to the initial Chatbot through the browser so it can respond back.

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

Install

$ agentstack add mcp-maxmedawar-tandem

Open-source listing, not yet scanned by AgentStack. Follow the source repository for install instructions.

Security review

⚠ Flagged

1 finding(s); flagged for manual review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures
  • high Pipes remote content directly into a shell (remote code execution).

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • 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 →

Reliability & compatibility

Not yet reviewed
0 installs to date
no reviews yet
3mo 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 Tandem? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Run and manage Claude Code sessions from your Claude.ai chat, and it talks back on its own.

=22.6">

An MCP bridge that lets a chat AI (Claude.ai, ChatGPT) spawn and drive real Claude Code sessions on your own machine.

What it is

tandem is a bridge between a chatbot and your computer: the chat AI connects over a URL you control and drives real, interactive Claude Code sessions running locally — opening them, sending work, and reading back results — while you watch or type alongside in your own terminal. It can also run two sessions autonomously: a manager that plans and reviews hands work to a worker that builds, relaying back and forth with no human in the loop. Everything runs on your machine; the only thing that leaves it is the tunnel you started yourself.

Quick start

Set up with Claude Code (easy, automated - recommended)

Paste the prompt below into a new Claude Code session — it does the whole install for you and pauses with simple instructions whenever you need to click something in your own account.

You are setting up "tandem" on this machine for me. tandem is an MCP bridge (public repo: https://github.com/Maxmedawar/tandem) that lets my chat AI drive Claude Code sessions here over a persistent Tailscale Funnel URL. Do the whole setup yourself and only stop when you genuinely need me to click something in my own account.

- Run every network or tailscale command wrapped in `timeout 40` so nothing ever hangs forever. If a command times out, treat it as a failure, tell me plainly, and move to the matching STOP block below.
- Do the install steps silently. Do not explain what you are about to do or narrate progress. Only talk to me when you hit a STOP block or when you are finished.
- You CANNOT click inside my browser or my Tailscale account. When a step needs that, use a STOP block: print the exact simple instructions, then wait for me before doing anything else. Never guess past a STOP. When I reply: if I say "continue" or "done", re-check the step worked and move on; if I describe a problem or say I am stuck, help me fix it in plain language, then continue once it is sorted.
- Keep STOP instructions plain and non-technical: numbered, short, no jargon. Give me the exact link to click when there is one.
- Never print my token anywhere except the single final MCP URL at the very end.

1. PREREQS. Check for: Node 22.6+, tmux, the `claude` CLI, and `tailscale`. Install whatever is missing using the system package manager (on macOS use Homebrew; Tailscale on macOS is `brew install --cask tailscale-app`, the standalone app - the Mac App Store version does not work). If a tool cannot be auto-installed, use a STOP block telling me how to install it.

2. TAILSCALE LOGIN. Run `timeout 40 tailscale status`. If it says logged out / needs login / not running, do this STOP block:
   PAUSE. One quick thing:
   1. Open the Tailscale app on this computer.
   2. Click "Log in" and sign in (any account, it is free).
   3. Wait until it says Connected.
   Then come back here and type: continue

3. GET THE CODE. If a `tandem` folder is not already here, run `git clone https://github.com/Maxmedawar/tandem.git`. cd into it.

4. FREE THE PORT. Run `lsof -ti:8787 | xargs kill -9 2>/dev/null` to clear any old bridge, ignore errors.

5. TURN ON THE FUNNEL (this is where the two one-time account switches live). Run `timeout 40 tailscale funnel --bg 8787` and read the result:
   - If it succeeds, continue to step 6.
   - If the output mentions Funnel is not enabled / not permitted / a node attribute, it will include a link. Do this STOP block, pasting the real link it gave:
     PAUSE. One quick switch to flip (takes 30 seconds):
     1. Open this link: 
     2. Click the button to turn Funnel on.
     3. Come back here and type: continue
   - If the output mentions HTTPS is not enabled / certificates, do this STOP block:
     PAUSE. One quick switch to flip (takes 30 seconds):
     1. Open this link: https://login.tailscale.com/admin/dns
     2. Find "HTTPS Certificates" and click Enable.
     3. Come back here and type: continue
   After I type continue, run the same funnel command again. Repeat until it succeeds (I may need to flip both switches, one at a time).

6. START THE BRIDGE + PRINT THE URL. Run `TANDEM_SETUP_MODE=tailscale ./setup.sh`. It installs deps, reuses or makes the token, starts the bridge, and prints the MCP URL. If it asks anything interactively, pick tailscale.

7. VERIFY. Get my funnel hostname from `tailscale status --json` (the DNSName), then run `timeout 40 curl -s -o /dev/null -w "%{http_code}" https:///health`. It must print 200. If it does not, tell me plainly what failed and stop.

When /health returns 200, print exactly this and nothing else after it:

tandem is live. Here is your connector:

   URL:  /mcp>

To connect it in Claude.ai:
   1. In the left sidebar, click your name / "Customize", then click "Connectors".
   2. At the top of the Connectors panel, click the three dots (...) and choose "Add custom connector".
   3. Give it a name: Tandem
   4. Paste the URL above into the URL field (the second box). Click enter.
   5. That is it - you are set.

Then install the "Claude for Chrome" extension and sign in, and in any chat say: start tandem

(If Claude.ai ever asks you to "sign in" to the connector instead of just adding it, the URL is wrong - re-paste the full one above, including the part after the last slash.)

(You need Claude Code installed first: npm i -g @anthropic-ai/claude-code, which needs Node 22.6+. Then run claude. The same prompt lives in [SETUP-PROMPT.md](SETUP-PROMPT.md).)

Set up yourself (not recommended)

  1. Install the prereqs:
  • Node 22.6+
  • tmux
  • Claude Code CLI (claude)
  • Tailscale:
  • macOS: brew install --cask tailscale-app (the standalone GUI app; the Mac App Store version does not support Funnel)
  • Linux: curl -fsSL https://tailscale.com/install.sh | sh
  1. Get tandem: git clone https://github.com/Maxmedawar/tandem.git && cd tandem && ./setup.sh
  2. Pick Tailscale when the script asks which mode (it's the default — just press Enter). You get a permanent URL you set up once and never touch again.
  3. Sign into Tailscale when prompted — open the Tailscale app and log in (one time, free account).
  4. Copy the MCP URL the script prints (https://..ts.net//mcp).
  5. Paste it into your chat app: Claude.ai or ChatGPT → Settings → Connectors → Add custom connector.
  6. Install the Claude Chrome extension ("Claude for Chrome" from the Chrome Web Store) and sign in — this lets sessions report back to your chat.
  7. Say "start tandem" in your chat, and you're off.

Full walkthrough + troubleshooting: see [SETUP.md](SETUP.md).

How it works

tandem runs a small MCP server on your machine and exposes it one of three ways:

  • Tailscale Funnel (recommended): a persistent public URL — https://..ts.net — that never changes across restarts. Free on every Tailscale plan, real HTTPS, no interstitial page. One-time login, then set-and-forget.
  • Cloudflare quick tunnel: a free, anonymous https://.trycloudflare.com URL — no account at all, but the URL changes every run.
  • Local stdio (desktop): no network, no tunnel — for Claude Desktop / ChatGPT desktop.

A chat AI connects to that URL and can open a real, interactive claude session, talk to it, and watch it work, while you sit at the same terminal.

Sessions are real interactive Claude Code TUIs running inside tmux (ccm-), driven by keystroke injection and screen scraping against the genuine claude CLI. You can tmux attach -t ccm- to watch or type alongside the AI. Everything runs locally; the only thing that leaves your machine is the tunnel you started yourself.

Capabilities

  • Drive a live Claude Code session — open, send turns to, and read back from an interactive claude session running locally in tmux.
  • Shared live session — you and the chat AI both interact with the same tmux session; tmux attach lets you watch or type alongside, and reads are incremental (cursor-based) so neither side blocks the other.
  • Turn-completion detectionsend_to_session holds open until the turn finishes (detected via Claude Code's "esc to interrupt" marker plus screen-stability); if a turn runs long it returns status:"running" and you poll read_session until idle:true.
  • Autonomous lead/worker relay — two interactive sessions message each other with no human in the loop: a lead strategist hands one step at a time to a worker and reviews results, relaying until the lead emits RELAY_DONE or a turn cap is hit. Steer it live with inject.
  • Persistent manager (park-and-wait) — the lead doesn't die when a task finishes: it parks (idle, alive, keeping its on-disk memory) and waits for the next task you enqueue, running each under a fresh per-task budget, until you stop it, it sits idle past a timeout, or it escalates that it's stuck.

What this can't do (honest limits)

  • It cannot wake the claude.ai chat tab. A remote MCP connector is

request/response; the stateless Streamable-HTTP transport here holds no standing server→client channel. tandem can emit a completion signal (events.log + optional webhook) and ping a device (your phone, via ntfy), but it cannot make the claude.ai chat send an unprompted reply. See Completion events / waking the client below.

  • The ntfy push reaches a device, not the chat. It tells you the work is

done so you can return to the chat — it does not resume the conversation.

  • It is not a hosted/multi-tenant service. Each user runs their own local

bridge and their own tunnel; there is no shared server.

  • Automating Claude is on you. tandem drives the official claude CLI through

automated and sometimes unattended means; depending on how you auth it, this may fall under Anthropic's Consumer Terms restrictions on automated access. Run it on your own account at your own risk; an Anthropic API key is the cleanly-permitted path for autonomous use.

Tools

Six tools:

  • open_session — spawn an interactive session in an allowlisted dir. Skip-permissions (autonomous) by default; optional model / effort set the session model and thinking effort (session-scoped, via claude --model / --effort).
  • list_sessions — list live + recent sessions.
  • send_to_session — send a prompt and wait (bounded by TANDEM_WAIT_MS) for the turn; returns the report, or status:"running" to call again. Omit text for poll mode (fetch new output since cursor without sending) — this replaces the old read_session. Accepts slash commands verbatim (see below) and optional per-turn model / effort overrides.
  • interrupt_session — Ctrl-C the current turn, keep the session.
  • close_session — kill the session.
  • relay — one tool with action: start | read | enqueue | inject | stop for the autonomous lead/worker relay (replaces the old start_relay / read_relay / inject_to_relay / stop_relay). The lead is a persistent manager: when a task finishes it parks and waits; enqueue hands it the next task (see Persistent manager below).

Consolidated from 10 → 6; no capability was removed (the underlying routes are unchanged and still reachable).

Autonomy & control

Skip-permissions by default. Spawned sessions launch with --dangerously-skip-permissions so autonomous turns don't stall on allow-prompts. Disable per host with TANDEM_SKIP_PERMISSIONS=0. This is contained: it only suppresses Claude Code's in-session tool prompts. The cwd allowlist is enforced before every spawn (in open_session/relay and again inside the engine's spawn), and the pane is created in the already-validated cwd — so skipping prompts can never widen which directories are reachable. (On a host that has never accepted bypass mode and lacks skipDangerousModePermissionPrompt, Claude Code shows a one-time acceptance dialog; the engine auto-accepts it on warmup.)

Model & effort. Set them per session at open time, or override per turn on send:

| Param | Accepted values | |---|---| | model | alias default / opus / sonnet / haiku, or a full claude-* id (e.g. claude-opus-4-8) | | effort | low / medium / high / xhigh / max |

  • open_session{ model?, effort? } → session-scoped claude --model / --effort flags (no global side effect).
  • send_to_session{ model?, effort? } → applied to that turn via in-session /model / /effort controls (these also persist as Claude Code's saved default for new sessions — prefer open-time for strictly session-scoped control).
  • Unsupported values are rejected with a clear 400, never silently ignored.

Slash-command passthrough. Any slash command sent as send_to_session's text reaches the TUI verbatim and executes — the autocomplete's exact match resolves on the submit. Examples:

send_to_session { "name": "s1", "text": "/status" }     // session/model/account status
send_to_session { "name": "s1", "text": "/mcp" }        // MCP server status
send_to_session { "name": "s1", "text": "/model opus" } // switch model
send_to_session { "name": "s1", "text": "/goal ship the parser" } // custom command

Completion events / waking the client

tandem emits a completion event the moment a turn or relay finishes — you don't have to keep polling to learn that work is done. Detection reuses the engine's proven idle/done logic (the "esc to interrupt" marker + screen-stability for turns; RELAY_DONE / cap for relays).

What is emitted — a JSON object:

{ "ts": "…", "type": "session", "status": "done", "id": "", "cursor": 12345, "summary": "…", "reason": "…", "handoff": "CC check — session \"…\" finished (done).\nSummary: …\nCommit: …\nFiles changed: …\nNext: …" }

The handoff field is a chat-ready, copy-pasteable plain-text block (also used as the phone notification body — see Phone notifications below).

Where it goes (the EMIT side, which this repo implements):

  1. ~/.tandem/events.log — one JSON line is appended per completion. Durable; tail -f it or have any local process watch it.
  2. TANDEM_DONE_WEBHOOK — if set, the same JSON is POSTed to that URL (fire-and-forget, no deps). Point it at any local listener, notifier, or automation.

Phone notifications (ntfy)

For a real buzz on your phone when a session finishes, tandem can push to ntfy (free, no account) on top of the event emit above. It's off until you set a topic. Three steps:

  1. Install the ntfy app (iOS App Store / Google Play), or use the web app.
  2. Subscribe to a topic in the app — pick a long, hard-to-guess name (anyone

who knows the topic can read it), e.g. tandem-9f3a2c-done.

  1. Set TANDEM_NTFY_TOPIC in your .env to that exact topic (and optionally

TANDEM_NTFY_SERVER if you self-host ntfy; default https://ntfy.sh).

Now each completion sends a notification titled tandem: done whose body is a chat-ready handoff block — the same plain-text block written to events.log and POSTed to the webhook. On the phone it looks like:

🔔 tandem: my-session done
CC check — session "my-session" finished (done).
Summary: added the handoff block to completion events
Commit: 880f6e0
Files changed: 3
Next: Review the session output and decide the next step.

The notification carries a Click action pointing at https://claude.ai, so tapping it opens claude.ai on your phone. There you paste check (or paste the handoff block itself) and the chat Claude immediately picks up — it knows what finished, the commit, how many files changed, and what to do next, without you re-typing any context. The POST is fire-and-forget; if ntfy is unreachable the failure is logged t

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.