@bazaar.ai/mcp-human-agents
v0.2.7
Published
MCP server for summoning human contractors into VMs
Readme
Bazaar MCP Server
The MCP server that lets an AI agent (Claude Code, etc.) summon a real human contractor when it gets stuck. Posts a gig to the Bazaar platform, waits for a contractor to be matched, provisions their access, and opens a reverse tunnel so the contractor can connect via the web terminal — no ngrok or public IP needed.
Quick Setup (3 steps)
1. Sign up & get an API key
- Create an account on the Bazaar dashboard
- Go to API Keys in the sidebar and click Create Key
- Copy the key (
bzr_live_...) — you won't see it again
2. Run the setup script
npx @bazaar.ai/mcp-human-agents --setup --api-key=bzr_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxThe setup script will:
- Check for prerequisites (sshd, tmux, git) and offer to install them
- Validate your API key against the platform
- Configure sudo permissions for contractor provisioning
- Register the MCP server with Claude Code
3. Restart Claude Code
Restart Claude Code so the new MCP server is picked up. Verify with:
claude mcp list
# → bazaar npx @bazaar.ai/mcp-human-agentsThat's it. Ask Claude to "summon a human contractor" and the platform handles matching, provisioning, and connectivity automatically.
How It Works
Developer Machine Bazaar Platform
├── Claude Code ├── human-layer API
│ └── bazaar MCP server │ ├── gig matching
│ ├── creates local user │ ├── ephemeral SSH keys
│ ├── configures SSH + tmux │ └── web terminal relay
│ └── opens reverse tunnel ─────► │
│ └── Dashboard
Contractor (anywhere) ├── gig notifications
└── Browser ─► web terminal ─────────────────┘- Claude Code calls
summon_human→ MCP server creates a gig on the platform - Platform auto-matches an available contractor
- MCP server provisions a Linux user, SSH key, and tmux session locally
- MCP server opens a reverse WebSocket tunnel back to the platform
- Contractor opens the web terminal in the dashboard
- Terminal traffic flows: browser → platform → tunnel → local sshd
- When done, Claude calls
dismiss_human→ cleanup + tunnel close
MCP Tools
| Tool | Description |
|------|-------------|
| summon_human | Post a gig, match a contractor, provision access |
| dismiss_human | Revoke access, optionally merge changes, report completion |
| list_humans | List active contractors on this machine |
| message_human | Send a message to a contractor's tmux session |
Configuration
The setup script handles configuration automatically. For reference, these are the environment variables used:
| Variable | Default | Description |
|----------|---------|-------------|
| PLATFORM_API_URL | http://localhost:3000 | Bazaar platform API endpoint |
| PLATFORM_API_KEY | (required) | Your Bazaar API key |
| USE_MOCK_PLATFORM | false | Set true for offline testing with mock data |
| TUNNEL_ENABLED | true | Reverse tunnel mode (no ngrok needed) |
| PROVISIONING_USE_SUDO | false | Use sudo for privileged commands |
| VM_EXTERNAL_IP | auto | Only needed when TUNNEL_ENABLED=false |
| VM_EXTERNAL_SSH_PORT | 22 | Only needed when TUNNEL_ENABLED=false |
| PLATFORM_PROJECT_ID | (auto) | Auto-created on first gig if omitted |
| POLL_TIMEOUT_MS | 300000 | Max wait for contractor matching (5 min) |
| STATE_FILE_PATH | /var/lib/human-agents/state.json | Crash recovery state |
Platform Support
The MCP server's sandbox desktop mode (connectionMode="rdp-sandbox")
provisions contractors into dedicated xfce4 sessions via xrdp, and
the shared-screen mode (connectionMode="shared-screen") attaches
x11vnc to the developer's own live $DISPLAY. Both rely on
Linux-only tooling — they shell out to apt, systemctl, useradd,
chpasswd, loginctl, and x11vnc. We don't (yet) ship a native
Windows RDS path or a native macOS Screen-Sharing path.
Rather than fragment the provisioning code across three OSes, we
formalize "the MCP server runs on Linux" as the supported contract and
steer Windows/macOS users onto an official Linux compatibility layer.
summon_human runs a preflight check at RDP provisioning time and
fails fast with a setup pointer if it detects a non-Linux host.
The direct-tmux connection mode does not require any of this and
works natively on Linux, macOS, and Windows (it only needs tmux and
sshd), so if you don't need dedicated desktops for your contractors,
you can skip this section entirely.
Running on Windows (via WSL2)
WSL2 ships with Windows 10 22H2+ and Windows 11 and gives you a real
Linux kernel. xrdp + xfce4 run inside it unchanged.
Install WSL2. From an admin PowerShell:
wsl --installThis installs Ubuntu by default. Reboot when prompted.
Enable systemd inside WSL.
xrdpis a systemd service, so the default WSL init won't cut it. Inside the Ubuntu shell:sudo tee -a /etc/wsl.conf >/dev/null <<'EOF' [boot] systemd=true EOFThen from PowerShell on the Windows side:
wsl --shutdownReopen Ubuntu. Confirm with
systemctl is-system-running— it should sayrunningordegraded(notoffline).Run the setup script from inside WSL. Everything from the Quick Setup section above works unchanged inside the Ubuntu shell.
Keep
TUNNEL_ENABLED=true(the default). WSL2 runs behind a NAT'd vEthernet adapter, so port 3389 is not reachable from outside the Windows host by default. The reverse tunnel dials outward from inside WSL and sidesteps the whole problem. If you genuinely need direct RDP, you have two options:- Port proxy (any WSL2 version): from an admin PowerShell,
netsh interface portproxy add v4tov4 listenport=3389 connectaddress=<wsl-ip> connectport=3389. The WSL IP changes on every reboot, so you'll want a startup script. - Mirrored networking (Windows 11 23H2+): add
[wsl2]\nnetworkingMode=mirroredto%UserProfile%\.wslconfigandwsl --shutdown. WSL2 then shares the Windows network stack and 3389 just works — but it will conflict with Windows' own RDS if you have that enabled on the same port.
The MCP server will log a warning if it sees
TUNNEL_ENABLED=falsewhile running inside WSL2.- Port proxy (any WSL2 version): from an admin PowerShell,
Why not native Windows RDS? Windows Pro/Enterprise ships a real RDP server built in. We could, in principle, add a second provisioning backend that enables RDS via
Set-ItemProperty ... fDenyTSConnections, creates users withNew-LocalUser, and adds them to the "Remote Desktop Users" group. We chose not to because (a) it doesn't work on Windows Home (no inbound RDP), (b) it would require a parallel PowerShell code path for user/session/cleanup management, and (c) WSL2 keeps the contractor UX identical to Linux. If you have a compelling reason to want native RDS, open an issue — the hooks are already insrc/provisioning/host-platform.ts.
Running on macOS (via OrbStack / Lima)
macOS has no native RDP server — Apple only ships the client. Screen Sharing uses VNC on port 5900, which is a different protocol. Rather than add a whole VNC code path, run the MCP server inside a Linux VM.
Recommended options, lightest first:
OrbStack — nearly invisible, boots in under a second, built specifically for Mac. Create an Ubuntu machine:
orb create ubuntu bazaar orb -m bazaarThen run the setup script from inside the Ubuntu shell.
Lima — open-source, scriptable, a bit more plumbing:
limactl start --name=bazaar template://ubuntu-lts limactl shell bazaarDocker Desktop — works but heaviest. You'll need a privileged long-running Ubuntu container with systemd enabled. Prefer OrbStack or Lima if you have the choice.
Port forwarding from the Linux VM to the Mac host is handled by the VM
runtime (OrbStack and Lima do it automatically). As with WSL2, you
should keep TUNNEL_ENABLED=true so contractors can reach you without
any manual port plumbing.
Why not native macOS VNC? macOS has
launchctl-managed Screen Sharing and Apple Remote Desktop (port 5900, VNC protocol). Enabling it programmatically is possible via/System/Library/CoreServices/RemoteManagement/ARDAgent.app/ Contents/Resources/kickstart, and users can be created withsysadminctl -addUser. The blockers are (a) contractors would need a VNC client instead of xfreerdp, which breaks the uniform "xfreerdp /v:..." connection string the platform hands out, (b) macOS requires Screen Recording + Accessibility TCC permissions that cannot be granted without user interaction, and (c) it's a second parallel cleanup code path. Running inside a Linux VM keeps one provisioning backend and one contractor UX. Hooks for a futureMacVncProviderlive insrc/provisioning/host-platform.ts.
Advanced: Manual Setup
If you prefer to configure everything manually instead of using the setup script:
1. Install prerequisites
sudo apt-get update
sudo apt-get install -y openssh-server tmux git curl
sudo service ssh start2. Configure sudoers (if not running as root)
Replace <youruser> with your username (whoami):
sudo tee /etc/sudoers.d/bazaar-mcp >/dev/null <<'EOF'
<youruser> ALL=(root) NOPASSWD: /usr/sbin/useradd, /usr/sbin/userdel, /usr/sbin/usermod, /usr/bin/pkill
<youruser> ALL=(root) NOPASSWD: /usr/sbin/sshd, /bin/systemctl reload sshd, /bin/systemctl reload ssh, /usr/sbin/service ssh reload
<youruser> ALL=(root) NOPASSWD: /usr/bin/tee, /bin/chmod, /bin/chown, /bin/cp, /bin/mkdir
<youruser> ALL=(ALL:ALL) NOPASSWD: /usr/bin/tmux
EOF
sudo chmod 0440 /etc/sudoers.d/bazaar-mcp
sudo visudo -c # Must print "parsed OK"3. Register with Claude Code
claude mcp add bazaar \
-e PLATFORM_API_URL=http://localhost:3000 \
-e PLATFORM_API_KEY=bzr_live_xxxx \
-e USE_MOCK_PLATFORM=false \
-e TUNNEL_ENABLED=true \
-e PROVISIONING_USE_SUDO=true \
-- npx @bazaar.ai/mcp-human-agents4. Legacy direct-SSH mode (no tunnel)
If you need contractors to SSH directly (e.g., for debugging), disable the tunnel and provide a public endpoint:
claude mcp add bazaar \
-e PLATFORM_API_URL=http://localhost:3000 \
-e PLATFORM_API_KEY=bzr_live_xxxx \
-e USE_MOCK_PLATFORM=false \
-e TUNNEL_ENABLED=false \
-e VM_EXTERNAL_IP=0.tcp.ngrok.io \
-e VM_EXTERNAL_SSH_PORT=17832 \
-e PROVISIONING_USE_SUDO=true \
-- npx @bazaar.ai/mcp-human-agentsTroubleshooting
sudo: a password is required
The sudoers file isn't being read. Run sudo visudo -c and check that
/etc/sudoers.d/bazaar-mcp exists and has mode 0440.
tmux: server failed to start
The contractor user's home directory may not exist. The MCP server runs
useradd -m which creates it. If you're seeing this, something is
wrong with your distro's useradd defaults.
Polling times out
No contractor is available, or the matching service isn't running.
Check the platform logs for autoMatch messages.
Tunnel WebSocket keeps reconnecting Check that the platform API is reachable from your machine. The tunnel client auto-reconnects with backoff on connection drops.
useradd: user '<name>' already exists
Leftover from a previous gig. Run sudo userdel -r <name> manually,
or call dismiss_human to clean up properly.
