Skip to main content
Glama
quochuy
by quochuy

ai-coord-mcp

A shared coordination layer between multiple AI coding assistants — not an orchestrator.

This MCP server never launches, manages, or talks to any AI process. It only exposes a task queue, a per-task message thread, and progress reporting, all persisted as human-readable JSON on disk. Claude Code and OpenCode (or any other MCP-capable client) are launched manually, in separate terminals, and both point their MCP config at this server. Claude typically plays coordinator (creates/reviews tasks); OpenCode plays implementer (claims/updates/completes them) — but the server has no opinion about that, it just stores state.

Claude Code (Sonnet)                    OpenCode (DeepSeek/Qwen/etc.)
        │                                        │
        │ create_task, list_tasks,                │ claim_task, update_progress,
        │ approve_task, request_revision           │ complete_task, post_message
        ▼                                        ▼
              ai-coord-mcp  (this server)
                       │
                       ▼
              .ai/coordination/*.json  (on disk)

Design

  • Transport: stdio. Each client spawns its own copy of this server as a subprocess. "The same server" means the same storage directory (COORDINATION_DIR), not one process. Every tool call re-reads the relevant JSON file from disk before mutating it; writes go through temp-file-then-rename (writeJsonAtomic) so a reader never sees a half-written file; a cross-process mutex (withLock, src/storage/lock.ts) built on mkdir guards concurrent writers, with stale-lock reclaim after 10s and an ownership token per holder.

  • IDs: sequential task-0001, task-0002, … assigned under a short-lived lock. Validated against /^task-\d{4,}$/ before being joined into any filesystem path.

  • Optimistic concurrency: every task carries a version counter. Pass expected_version to any mutating tool to get a ConflictError instead of a silent overwrite.

  • Not implemented: binary attachments (the files field is path references only, not stored content), archiving (the archive/ directory exists but nothing writes to it), typed branch/commit fields (use the metadata convention below instead), structured Definition-of-Done / verify_command (use expected_output instead), task relationships / parent_id/blocks (use tags to group instead), MCP Resources / resources/subscribe (use wait_for_task instead).

Status model:

pending --claim_task--> claimed --update_progress--> in_progress
   ^                        |                              |
   |                        |     both claimed and in_progress can complete_task--> completed
   |                        |                                                            |
   |                        └──────────────────────cancel_task─────────────────┐  approve_task│request_revision
   |                                                                            |         |         |
   └───────────────reopen_task (from cancelled/completed/approved)◄────────────┘         ▼         ▼
                                                                                    approved   revision_requested
                                                                                               (loops back through
                                                                                                update_progress →
                                                                                                in_progress again)

update_progress auto-advances claimed or revision_requested to in_progress on its first call in that cycle — there's no separate "start_task" tool.

Related MCP server: MCP Agent Mail

Storage layout

.ai/coordination/
  tasks/task-0001.json       one file per task (includes its own audit history[])
  messages/task-0001.json    array of {id, taskId, author, timestamp, content}
  progress/task-0001.json    latest snapshot + full history of updates
  archive/                   reserved, unused
  .locks/                    transient lock directories, safe to delete if empty

Everything is plain JSON — cat .ai/coordination/tasks/task-0001.json works fine while the server is running.

Setup

cd ai-coord-mcp
pnpm install
pnpm run build

Both Claude Code and OpenCode need to point at the same COORDINATION_DIR (an absolute path) so they share state regardless of which directory each was launched from.

Claude Code — add to .mcp.json (project) or via claude mcp add:

{
  "mcpServers": {
    "ai-coord": {
      "command": "node",
      "args": ["/absolute/path/to/ai-coord-mcp/dist/index.js"],
      "env": {
        "COORDINATION_DIR": "/absolute/path/to/shared/.ai/coordination"
      }
    }
  }
}

OpenCode — add the equivalent entry to its MCP config (opencode.json / ~/.config/opencode/config.json, depending on your OpenCode version):

{
  "mcp": {
    "ai-coord": {
      "type": "local",
      "command": ["node", "/absolute/path/to/ai-coord-mcp/dist/index.js"],
      "environment": {
        "COORDINATION_DIR": "/absolute/path/to/shared/.ai/coordination"
      }
    }
  }
}

If COORDINATION_DIR is unset, the server defaults to <cwd>/.ai/coordination — only safe if you know both clients will be launched from the same working directory.

Getting started

  1. Build the server and wire up COORDINATION_DIR for both clients (Setup above).

  2. Launch Claude Code and OpenCode in separate terminals, both in the shared repo.

  3. In Claude Code, create a task:

    Create a task: title "Sort inventory list", description "Implement stable sort by SKU for the inventory panel, keep the existing filter hooks working", expected_output "inventory.ts updated, existing tests still pass, new test for empty list". → calls create_task, returns task-0001 (status pending).

  4. In OpenCode:

    Check ai-coord for any pending tasks. → calls claim_next_task, works the task, calls update_progress a few times, then complete_task.

  5. Back in Claude Code:

    Review task-0001 and approve or request revision. → reviews the diff, calls approve_task or request_revision (the latter posts feedback to the thread; OpenCode reads it via get_messages and repeats from update_progress).

Tools

Tool

Purpose

create_task

Create a task (status pending)

list_tasks

List task summaries (no history[], includes computed idleSeconds), filter by status / assignee / creator / tag

get_task

Fetch one task by id, full record including history[]

search_tasks

Substring search over title/description/tags, same summary shape as list_tasks

claim_task

pendingclaimed

claim_next_task

Atomically claim the first eligible pending task (optionally by tag) instead of a list_tasks + claim_task round trip; returns null if none available

wait_for_task

Block (polling, lock-free) until a task's status changes or timeout_seconds elapses, instead of looping get_task yourself

complete_task

claimed/in_progress/revision_requestedcompleted

approve_task

completedapproved

request_revision

completedrevision_requested (also posts the feedback as a message)

cancel_task

any open status → cancelled

reopen_task

cancelled/completed/approvedpending, clears assignee

post_message

Append to a task's conversation thread

get_messages

Read a task's thread, optionally only messages since an ISO timestamp

update_progress

Report percent (0-100) / current_step / notes; auto-advances status to in_progress

get_progress

Latest progress snapshot + history

All mutating tools accept an optional expected_version — pass the task's current version to get a ConflictError instead of clobbering a concurrent change.

Every status-changing tool above (claim_task through reopen_task) returns the same summary shape as list_tasks — no history[] — so an implementer with a small context window (a local model, say) isn't handed the whole growing transition/note log back on every call. Same for update_progress: it returns the current snapshot, not the growing history[]. get_task/get_progress remain the only tools that return full history.

Workflow conventions

  • Waiting for work: use wait_for_task over polling get_task/list_tasks — one call instead of N, blocks server-side without holding a lock, returns timed_out: true as a normal result.

  • Picking up work: use claim_next_task over list_tasks({status:"pending"}) + claim_task — same two steps, atomic, retries automatically if another claimer wins the race.

  • Git state: no typed branch/commit field. Convention: create_task's metadata carries { baseCommit, branch }; both agents read/write those same keys. expected_output plus this README is the Definition-of-Done contract.

  • Implementer loop: claim_next_task (or claim_task on a specific id) → work → a few update_progress calls → complete_task. If revision is requested, get_messages for the feedback, then repeat from update_progress.

  • Coordinator loop: create_taskwait_for_task (or check back later) → on completed, review the diff at working_directoryapprove_task or request_revision.

Tests

pnpm test

Runs node:test (via tsx) over every src/**/*.test.ts file: the storage layer (atomic writes, cross-process lock semantics including the stale-lock/ownership-token edge case, id generation, message/progress persistence) and the full tool surface (state-machine transitions, TASK_ID schema rejecting malformed/traversal ids, version conflicts) driven through the real registerXxx() functions against a fresh temp COORDINATION_DIR per test file.

A
license - permissive license
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    -
    quality
    A
    maintenance
    A coordination layer for coding agents that provides memorable identities, inbox/outbox messaging, searchable message history, and file lease management to prevent conflicts. Uses Git for human-auditable artifacts and SQLite for fast queries, enabling multiple agents to collaborate across projects without stepping on each other.
    2,079
    MIT
  • A
    license
    -
    quality
    D
    maintenance
    A coordination layer for coding agents that provides identities, message threading, and searchable history. It features file reservation leases to prevent agents from overwriting each other's work in multi-agent environments.
    1
    MIT

View all related MCP servers

Related MCP Connectors

  • Durable agent-to-agent handoffs and shared scratchpad for multi-agent workflows.

  • The team layer for AI coding agents: shared contracts, collision alerts, E2EE sessions.

  • One shared brain for your AI coding agents: team memory, agent Q&A, tasks, and file claims.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/quochuy/ai-coord-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server