MCP server for AI agent pair-programming coordination. Driver/worker orchestration, task management, shared planning, and knowledge indexing.
curl -fsSL https://raw.githubusercontent.com/jaakkos/stringwork/main/scripts/install.sh | shSupports macOS (arm64, amd64) and Linux (amd64, arm64). Pass --version v0.1.0 for a specific release or --dir /usr/local/bin to change the install location.
Or build from source:
go build -o mcp-stringwork ./cmd/mcp-serverStringwork uses a driver/worker model:
Driver (Cursor)
|
|-- creates tasks, monitors progress, cancels stuck workers
|
+-- Worker 1 (Claude Code) -- claims tasks, reports progress, sends findings
+-- Worker 2 (Codex) -- claims tasks, reports progress, sends findings
+-- Worker 3 (Gemini CLI) -- claims tasks, reports progress, sends findings
+-- Worker N (any agent) -- ...assigned_to='any' for auto-assignment), monitors workers via worker_status, and cancels stuck agents with cancel_agent.~/.config/stringwork/state.sqlite).The server provides only coordination tools. Each agent uses its own native capabilities for file editing, search, git, and terminal.
set_presence workspace='...'register_agentAdd to .cursor/mcp.json in your project:
{
"mcpServers": {
"stringwork": {
"command": "mcp-stringwork",
"env": { "MCP_CONFIG": "/path/to/config.yaml" }
}
}
}Cursor spawns the server as a subprocess via stdio. With daemon mode enabled (recommended), the first Cursor window starts a background daemon and subsequent windows share it automatically.
Copy mcp/config.yaml and customize. Minimal example:
workspace_root: "/path/to/your/project"
enabled_tools: ["*"]
# Daemon mode: multiple Cursor windows share one server.
daemon:
enabled: true
# Fixed port for a stable dashboard URL. Use 0 for auto-assign.
http_port: 8943
orchestration:
driver: cursor
workers:
- type: claude-code
instances: 1
command: ["claude", "-p", "You are claude-code. Steps: 1) set_presence 2) read_messages 3) list_tasks 4) Do the work 5) report_progress 6) send_message with findings.", "--dangerously-skip-permissions"]
timeout_seconds: 600Open Cursor -- the server starts automatically. Create tasks, workers get spawned:
# Driver (Cursor) creates a task
create_task title='Add auth middleware' assigned_to='any' created_by='cursor'
# Server spawns a worker, which claims and works on it
# Driver monitors via:
worker_statusEnable daemon mode so multiple Cursor windows share a single server process:
daemon:
enabled: true
grace_period_seconds: 10The first Cursor window starts a background daemon. Subsequent windows connect to it as lightweight proxies. Workers, notifier, and watchdog run once -- no duplicates. The HTTP port and dashboard URL stay stable across reconnects. When the last window closes, the daemon waits for the grace period then shuts down.
Use --standalone to bypass daemon mode.
Without daemon mode, each Cursor window spawns its own server. With http_port: 0 (default), each gets an auto-assigned port so they don't conflict. All instances share the same SQLite state file, so tasks and messages are visible across all windows.
orchestration:
driver: cursor # which agent is the driver
assignment_strategy: least_loaded # or capability_match
heartbeat_interval_seconds: 30
worker_timeout_seconds: 120
worktrees:
enabled: false # git worktree isolation per worker
workers:
- type: claude-code
instances: 2 # run up to 2 Claude Code workers
command: ["claude", "-p", "...", "--dangerously-skip-permissions"]
cooldown_seconds: 30
timeout_seconds: 600
max_retries: 2
env:
GH_TOKEN: "${GH_TOKEN}" # ${VAR} expands from server env
SSH_AUTH_SOCK: "${SSH_AUTH_SOCK}"
# inherit_env: ["HOME", "PATH", "GH_*", "SSH_*"] # restrict inherited env
- type: codex
instances: 1
command: ["codex", "exec", "--sandbox", "danger-full-access", "--skip-git-repo-check", "..."]
- type: gemini
instances: 1
command: ["gemini", "--yolo", "--prompt", "..."]
env:
GOOGLE_API_KEY: "${GOOGLE_API_KEY}"See mcp/config.yaml for a fully annotated example.
| Tool | Description |
|---|---|
get_session_context | Full session context (messages, tasks, presence, plans) |
set_presence | Update status and workspace; dynamically changes server's project context |
append_session_note | Add shared note or decision |
| Tool | Description |
|---|---|
send_message | Message an agent (optional title, urgency) |
read_messages | Read and mark messages as read |
| Tool | Description |
|---|---|
create_task | Create task with optional work context (relevant_files, background, constraints) |
list_tasks | List tasks with filters |
update_task | Update status, assignment, priority; auto-notifies on completion |
| Tool | Description |
|---|---|
create_plan | Create shared plan |
get_plan | View plan(s); omit ID to list all |
update_plan | Add or update plan items with acceptance criteria |
| Tool | Description |
|---|---|
handoff | Hand off work with summary and next steps |
claim_next | Claim next task (dry_run to peek) |
request_review | Request code review from an agent |
| Tool | Description |
|---|---|
worker_status | Live view of workers: progress, SLA status, process activity |
heartbeat | Signal liveness every 60-90s with progress info. Include session_id on first call for session resume on restart |
report_progress | Structured progress: description, percent complete, ETA |
cancel_agent | Cancel a worker's tasks, send STOP signal, kill process |
get_work_context | Get task context (files, background, constraints, notes) |
update_work_context | Add shared notes to a task's work context |
| Tool | Description |
|---|---|
lock_file | Lock, unlock, check, or list file locks |
register_agent | Register a custom agent for collaboration |
list_agents | List all available agents (built-in and registered) |
Claude Code's CLAUDE.md instructions are wrapped in a "may or may not be relevant" framing that weakens compliance. Stringwork ships hooks that bypass this limitation:
./scripts/install-claude-hooks.sh # install hooks
./scripts/uninstall-claude-hooks.sh # clean removalHooks are installed at user level (~/.claude/settings.json) so they work across all projects. They inject progress reporting rules as clean system-reminder messages — no disclaimer, survives context compaction. Scripts have a guard and do nothing in non-Stringwork projects.
See Claude Code config for details.
mcp-stringwork # start server (auto-detects daemon/proxy/standalone)
mcp-stringwork --daemon # force daemon mode
mcp-stringwork --standalone # force standalone mode (no daemon)
mcp-stringwork --version # print version
mcp-stringwork status claude-code # check unread/pending counts for an agent.
├── cmd/mcp-server/ # Server entrypoint, daemon, proxy, CLI
├── internal/
│ ├── domain/ # Core entities (Message, Task, Plan, AgentInstance, ...)
│ ├── app/ # Application services (CollabService, WorkerManager, Watchdog, Orchestrator)
│ ├── repository/sqlite/ # State persistence (SQLite)
│ ├── policy/ # Workspace validation, config, safety policy
│ ├── dashboard/ # Web dashboard (HTML + REST API)
│ ├── worktree/ # Git worktree manager for worker isolation
│ └── tools/collab/ # 23 MCP tool handlers
├── chrome-extension/ # Chrome extension for toolbar monitoring (alpha)
├── cursor-plugin/ # Cursor IDE plugin (rules, skills, agents, commands, hooks)
├── mcp/ # Configuration files
├── scripts/ # Install, dev-install, hook install/uninstall scripts
├── docs/ # Documentation
├── .github/workflows/ # CI and release automation
├── AGENTS.md # Cursor agent instructions
└── CLAUDE.md # Claude Code agent instructionsStringwork ships a Cursor plugin that provides workflow rules, skills, agents, and commands for the driver role. The plugin structure is in cursor-plugin/ and ready for marketplace submission when the time comes.
curl -fsSL https://raw.githubusercontent.com/jaakkos/stringwork/main/scripts/install.sh | shOr add to your project's .cursor/mcp.json:
{
"mcpServers": {
"stringwork": {
"command": "mcp-stringwork"
}
}
}git clone https://github.com/jaakkos/stringwork.git /tmp/stringwork
/tmp/stringwork/scripts/install-cursor-plugin.shTo uninstall: ./scripts/uninstall-cursor-plugin.sh
For project-scoped installation instead of global, copy the plugin dirs into your project:
cp -r /tmp/stringwork/.cursor-plugin /tmp/stringwork/cursor-plugin your-project/mkdir -p ~/.config/stringwork
cp /tmp/stringwork/mcp/config.yaml ~/.config/stringwork/config.yaml
# Edit workers section, then start with: MCP_CONFIG=~/.config/stringwork/config.yaml| Component | Description |
|---|---|
| MCP server | Auto-configured mcp-stringwork connection |
| Rules (4) | Driver workflow, progress reporting, STOP signals, worker communication |
| Skills (4) | Setup guide, code review, task creation, worker configuration |
| Agents (2) | Pair programming driver, code review coordinator |
| Commands (1) | /pair-respond for processing worker messages |
| Hooks (1) | Binary existence check on session start |
The plugin is purely additive — it does not modify any existing project files.
A browser extension that brings Stringwork monitoring to your toolbar -- see worker status, task progress, and receive desktop notifications without switching to the dashboard.
What it does:
Architecture: The extension is built on Manifest V3 with a service worker that polls /api/state. All API access is centralized in the service worker; the popup communicates via chrome.runtime.sendMessage. State is persisted in chrome.storage.local to survive MV3 service worker termination. Background polling uses chrome.alarms (1-minute minimum); active polling at 5-second intervals only runs while the popup is open.
Install (unpacked, developer mode):
# ~/.config/stringwork/config.yaml
http_port: 8943chrome://extensions/chrome-extension/ directory from this repohttp://localhost:8943).Note: This is alpha software. The extension is functional but has not been published to the Chrome Web Store. After pulling code changes, reload the extension from
chrome://extensions/to pick them up.
jaakkos/stringwork
February 17, 2026
April 13, 2026
Go