agent-dispatch MCP server
2026년 11월 10일 커밋멀티 에이전트 오케스트레이션을 통해 Claude Code 에이전트가 다른 프로젝트 디렉토리에 있는 다른 에이전트에게 작업을 위임할 수 있도록 합니다.
다른 이름 ginkida/agent-dispatch
- 스타
- 31
- Tools
- 5
- 다운로드, 30일
- —
- 최신 버전
- —
- 마지막 커밋
- 2026년 11월 10일
- 라이선스
- MIT
agent-dispatch MCP란?
agent-dispatch은(는) MCP server입니다. 멀티 에이전트 오케스트레이션을 통해 Claude Code 에이전트가 다른 프로젝트 디렉토리에 있는 다른 에이전트에게 작업을 위임할 수 있도록 합니다. 5개 도구를 제공합니다. 예: name, preview_lines, description.
프로젝트 README에서 생성된 요약
agent-dispatch MCP server 정보
agent-dispatch는 Claude Code 사용자가 별도의 프로젝트 디렉토리에 있는 전문 에이전트에게 복잡한 작업을 위임할 수 있게 해줍니다. 여러 Claude Code 세션을 오케스트레이션함으로써, 기본 에이전트는 고유한 MCP server, CLAUDE.md 파일 및 도구 세트를 보유한 다른 에이전트에게 명령을 내릴 수 있습니다. 이를 통해 코드 저장소, 인프라 게이트웨이 또는 분석 플랫폼과 같은 다양한 환경에서 하나의 세션이 작업을 조정하는 분산 워크플로우를 구현할 수 있습니다.
사용자는 명령줄을 사용하여 로컬 프로젝트 디렉토리를 에이전트로 등록함으로써 시스템을 설정합니다. 이 서버는 OAuth, API 키 및 Claude 구독을 포함한 다양한 인증 방법을 지원합니다. 복잡성을 관리하기 위해 개발자는 컨텍스트와 설명을 공유하는 그룹으로 관련 에이전트를 묶을 수 있습니다. 시스템은 이러한 상호작용을 관리하기 위해 list_agents, inspect_agent, dispatch와 같은 도구를 제공합니다. 또한 사용자가 멀티 에이전트 워크플로우를 효과적으로 계획할 수 있도록 중앙값 비용 및 소요 시간과 같은 측정된 지표를 추적합니다.
활용 사례
- 1프로젝트 간 작업 위임개발자는 기본 에이전트에게 다른 디렉토리에 있는 인프라 에이전트로부터 컨테이너 로그를 요청하도록 지시할 수 있습니다.
- 2멀티 에이전트 그룹 조정오케스트레이션 세션은 코드, 배포 및 검증에 걸친 작업을 수행하기 위해 에이전트 그룹을 관리할 수 있습니다.
- 3비용 및 성능 계획사용자는 예상치 못한 비용 발생을 방지하기 위해 에이전트에게 작업을 보내기 전 일반적인 비용과 소요 시간을 확인할 수 있습니다.
프로젝트의 README를 바탕으로 작성되었습니다. 모든 활용 사례는 해당 내용의 인용문과 대조하여 확인합니다.
agent-dispatch MCP 도구 5
README에서 감지됨namepreview_linesdescriptionshared_contextagent
| name | — | |
| preview_lines | — | |
| description | — | |
| shared_context | — | |
| agent | — |
자동 검사
2026년 11월 13일에 실행됨전체 보고서 →아직 인증되지 않았습니다. 서버는 80점 이상의 점수, 심각한 결함 없음, 그리고 검사에 충분한 데이터를 갖추어야 합니다. 검사 방식 · 점수를 높이기 위해 수정할 항목
- 소스 저장소 연결 및 접근 가능ginkida/agent-dispatch is public and reachablegithub.com/ginkida/agent-dispatch ↗통과
- 패키지가 이 저장소를 소스로 명시검사되지 않음
- 빌드 출처(Sigstore 증명)검사되지 않음
- 오픈 소스 라이선스 (OSI)MITspdx.org/licenses/MIT.html ↗통과
- 최근 1년 내 커밋 또는 릴리스Last commit or release 2026-11-10github.com/ginkida/agent-dispatch ↗통과
- OpenSSF Scorecard검사되지 않음
- 패키지 이름이 인기 패키지와 유사하지 않음검사되지 않음
- 패키지 및 해당 종속성에 중요한 보안 권고 없음검사되지 않음
- 모델에 대한 숨겨진 지침 없음5 tool descriptions and the README read; no override phrases, credential paths or hidden characters통과
- 파괴적인 도구에 라벨 표시됨No tool named like delete, drop or exec통과
- 원격 엔드포인트가 MCP 핸드셰이크에 응답검사되지 않음
README
GitHub에서 보기agent-dispatch
MCP server that lets Claude Code agents delegate tasks to agents in other project directories.
Each agent runs as a separate claude -p session in its own project directory — inheriting that project's MCP servers, CLAUDE.md, and tools. The calling agent just gets the result back.
Related projects can be bundled into a group — a shared brief plus a member list — so one session can coordinate work across them (e.g. code repos + an infra/Portainer gateway + an analytics gateway).
Works with OAuth, API key, and Claude subscription authentication.
AI agents: this README is the canonical doc for using the tool — setup: Quick Start (every step has a deterministic verify), first call:
dispatch, tool selection: Which Tool to Use, failure handling: Error Recovery. Working on this repo instead? See AGENTS.md.
Quick Start
Prerequisite: the Claude Code CLI must be installed and authenticated. Check first:
claude --version # must print a version — if it fails, install Claude Code before continuing
Then:
pip install agent-dispatch # or: pipx install agent-dispatch
# 1. Create config + register the MCP server with Claude Code (user scope)
agent-dispatch init
# 2. Register project directories as agents — REPLACE the example paths with
# real directories on your machine; they must exist (~ is expanded, relative
# paths are resolved). Descriptions are auto-generated from project files.
# No second project handy? Use the zero-setup block below instead.
agent-dispatch add infra ~/projects/infra
agent-dispatch add backend ~/projects/backend
# 3. Smoke test — dispatches a real task to the agent added in step 2 and prints
# the answer; exit 0 on success. Default task when none given:
# "What project is this? Describe in one sentence."
agent-dispatch test infra
# 4. Verify the whole install — prints "All checks passed." and exits 0 on success
agent-dispatch doctor
Zero-setup alternative for steps 2–3 (no second project needed — registers the current directory):
agent-dispatch add self . && agent-dispatch test self "Say hello"
Every Claude Code session now has the dispatch tools. Independent check: claude mcp list must print a line starting with agent-dispatch:. From inside a Claude Code session, the first MCP calls are list_agents(), then dispatch(...).
If init fails to register the MCP server (prints a warning instead of Registered MCP server), register manually:
claude mcp add-json agent-dispatch "{\"type\":\"stdio\",\"command\":\"$(which agent-dispatch)\",\"args\":[\"serve\"]}" --scope user
If test fails with a permission error (error_type: "permission"), grant tool access and re-test:
agent-dispatch update infra --allowed-tools "Bash,Read,Grep" # least privilege
# or, if the agent needs everything (see SECURITY.md for the trade-off):
agent-dispatch update infra --permission-mode bypassPermissions
When to Dispatch
Do dispatch when a task needs tools, files, or context from another project:
- Check container logs via infra agent's Portainer MCP
- Query a database via db agent's postgres MCP
- Read code or run tests in another repository
Don't dispatch when you can do it yourself — dispatching spawns a full Claude session.
MCP Tools Reference
list_agents
Lists all configured agents. Call this first to see what's available.
// Response (capability + permission fields shown only when populated)
[
{
"name": "infra",
"directory": "/home/user/projects/infra",
"description": "Infrastructure agent. MCP: portainer. Stack: Python, Docker",
"healthy": true,
"has_claude_md": true,
"has_mcp_config": true,
"mcp_servers": ["portainer", "postgres"],
"stacks": ["Python", "Docker"],
"dbs": ["Alembic"],
"capabilities": ["docker_logs", "deploy_debug"],
"risky_capabilities": ["restart_services"],
"permission_mode": "bypassPermissions",
"allowed_tools": ["Bash", "Read", "Grep"],
"typical": {"median_seconds": 143.3, "p90_seconds": 178.3, "median_cost_usd": 0.2666}
}
]
mcp_servers, stacks, and dbs are detected from the agent's project files (.mcp.json, Dockerfile, pyproject.toml, Cargo.toml, prisma/, alembic.ini, etc.) so callers can pick the right agent without dispatching a probe.
typical is measured, not declared: it comes from this agent's own recent dispatches in the usage journal and appears only after a few runs. Use it to size timeout_seconds and to know what a call will cost before you make it. It is absent when the journal is off or the agent has too little history — no data is better than a typical duration derived from two runs.
inspect_agent
Cheap detailed lookup — reads the agent's files without spawning a claude session. Returns the full config (timeout, model, budget, permission mode, allowed/disallowed tools), detected MCP/stacks/DBs, plus short previews of CLAUDE.md and README.md when present.
| Parameter | Type | Required | Description |
|---|---|---|---|
name |
string | yes | Agent name from list_agents |
preview_lines |
int | no | Max lines of CLAUDE.md/README.md (default 40, max 200, 0 disables) |
Use this before dispatch_async/dispatch to confirm an agent has the tools and context for your task — much cheaper than a probe dispatch.
It also carries the agent's instructions (its standing orders) and the full typical block — the trimmed one in list_agents plus dispatches, failed and the outcomes breakdown:
"typical": {
"dispatches": 24, "median_seconds": 143.3, "p90_seconds": 178.3,
"median_cost_usd": 0.2666, "failed": 1, "outcomes": {"done": 21, "partial": 2}
}
Groups
A group bundles related agents into a cross-project working set — typically a few code repos plus capability gateways (an infra agent with a Portainer MCP, an analytics agent with a browser + Yandex Metrica). It lets one orchestrating session coordinate work that spans code, deploy, and verification.
A group is a descriptive layer, not an execution engine — there is no router and no state machine. You pick members by reading their hints and coordinate with the normal dispatch tools. Two text fields target two audiences:
description— orchestrator-facing: how to coordinate the group (the order of steps, who to call for what). Surfaced bylist_groups/inspect_group, never injected into a member's prompt.shared_context— member-facing facts (stack names, counter ids, conventions) that hold regardless of which member reads them. Auto-prepended to a member'scontextwhen you passgroup=.
Members reference agents by name; membership is many-to-many (a shared gateway can belong to several groups). Manage groups with the agent-dispatch group CLI (add/list/inspect/update/remove) or by editing agents.yaml.
list_groups() — cheap, no-subprocess readout of every group: description, member count, and each member's use_for hint + health. A member whose agent was removed is flagged "unknown": true rather than crashing.
inspect_group(name) — one group's full brief: description, the complete shared_context, and the member list. For a deep dive on a specific member, call inspect_agent(member) — inspect_group deliberately stays a cheap membership readout.
Using a group — pass group= to dispatch (or per-item in dispatch_parallel). The agent must be a member; its group's shared_context rides along automatically:
# From the shop-web codebase, hand the deploy to the infra gateway.
# The "shop" group's facts (stack name, counter id) are auto-attached.
dispatch(
agent="infra",
task="Redeploy the shop-web container",
caller="shop-web",
goal="ship the checkout fix",
group="shop",
)
group="" (the default) is byte-for-byte identical to a plain dispatch — the shared facts are folded into the context string, so the result cache disambiguates groups automatically and group-less calls are unaffected.
dispatch
One-shot task delegation. Results are cached — identical requests within TTL return instantly.
| Parameter | Type | Required | Description |
|---|---|---|---|
agent |
string | yes | Agent name from list_agents |
task |
string | yes | What to do — be specific, the agent has no context from your conversation |
context |
string | no | Extra context: error messages, code snippets, stack traces |
caller |
string | no | Your project/role — helps the agent understand who's asking |
goal |
string | no | Broader objective — helps the agent make better trade-offs |
response_format |
string | no | "json" to request a single JSON value; the parsed result lands in parsed_result. Empty = free-form text. |
return_ref |
bool | no | When true, returns just a ref + summary preview instead of the full result text. Use fetch_result(ref) to load the full text on demand. |
summary_chars |
int | no | Max chars of result text to include in the ref response (default 500). |
timeout_seconds |
int | no | One-off timeout override for this call (0 = agent's configured timeout; clamped to 10–7200). No config edit needed for known-long tasks. |
group |
string | no | Group name (from list_groups). The agent must be a member; the group's shared_context (member-facing facts) is auto-prepended to context. Empty = plain dispatch. See Groups. |
# Call — recommended form (always include caller and goal)
dispatch(
agent="infra", # must exist in list_agents()
task="Check container logs for errors related to the scheduler service",
context="Error: TypeError at scheduler.py:42",
caller="backend", # your project/role
goal="debug production crash" # the broader objective
)
// Response (success)
{
"agent": "infra",
"success": true,
"result": "Found 3 errors in container logs: TypeError in scheduler.py:42...",
"session_id": "sess-abc-123",
"cost_usd": 0.02,
"duration_ms": 5000,
"num_turns": 2,
"outcome": "done"
}
// Response (failure — error_type helps you handle programmatically)
{
"agent": "infra",
"success": false,
"result": "",
"error": "Tool_use is not allowed in this permission mode\n\nHint: ...",
"error_type": "permission"
}
error_type values: permission (tool/action denied), timeout, recursion (dispatch depth exceeded), not_found (missing directory or CLI), budget (the claude CLI stopped the session at max_budget_usd), usage_limit (the Claude account hit its rate/session limit), cli_error (other failures). Permission, budget, usage-limit and timeout errors include an actionable hint.
Resumable timeouts: every fresh dispatch pre-assigns a session UUID (--session-id), so a timed-out dispatch still returns a session_id — the partial transcript survives the kill. The timeout error spells out the recovery: resume with dispatch_session(agent, "Continue where you left off", session_id=...), retry with a bigger timeout_seconds, or use dispatch_async.
Denied-tools visibility: in non-interactive mode the claude CLI auto-denies tools the agent isn't allowed to use — the agent then often "succeeds" with an answer like "I need your permission for one read-only query". When that happens the response carries the deterministic signal: denied_tools (parsed from the CLI's permission_denials) plus a hint explaining the result may be incomplete and how to grant access. success stays true — it's a soft signal, not a failure.
// Response (success, but a tool was blocked)
{
"agent": "analysis",
"success": true,
"result": "Here is the offline mapping. To finish I'd need to run one read-only query...",
"denied_tools": ["Bash"],
"hint": "1 tool call(s) were denied by permissions: Bash. The result may be incomplete..."
}
Structured JSON output: pass response_format="json" to ask the agent for a single JSON value. The runner appends an instruction footer ("respond with a single valid JSON value, no fences, no prose") and on success parses the response — the parsed value lands in parsed_result. The raw text is always in result. Parse failures leave parsed_result=None but don't fail the dispatch (soft mode).
// Response with response_format="json"
{
"agent": "infra",
"success": true,
"result": "{\"errors\": 3, \"first_at\": \"14:02\"}",
"parsed_result": {"errors": 3, "first_at": "14:02"}
}
Always pass caller and goal — the dispatched agent sees a structured prompt:
## Goal
debug production crash
## Dispatched by
backend
## Context
Error: TypeError at scheduler.py:42
## Task
Check container logs for recent errors related to the scheduler service
The dispatch protocol and outcome. claude -p on its own does not know it is being driven by another agent: given an ambiguous task it will happily end with "Could you clarify which service you mean?" — a billed run that answered nothing, and one that a plain cache would then serve again for the whole TTL. So every dispatch also appends a short dispatch protocol to the agent's system prompt (--append-system-prompt, never mixed into your task text):
- it is running non-interactively, dispatched by
caller, and nobody will answer a question or approve an action — state the assumption and proceed, take the safer reading when two differ; - a denied tool or a missing thing is something to report, not something to stop on — finish everything else that is possible;
- its time budget is about the agent's timeout (and its spend cap, if one is set) — scope the work to fit; a complete partial answer beats an unfinished perfect one;
- lead with the outcome, then the evidence; list what could not be done and why (this is what makes a
return_refsummary — the head of the text — worth reading); - end with one line,
STATUS: done,STATUS: partialorSTATUS: blocked.
That last line is lifted out of result into outcome — the agent's own verdict, deterministic to check: "done" means complete; "partial" / "blocked" mean the agent says the work is unfinished, the result names what is missing, and a hint spells out the continuation (usually dispatch_session(..., session_id=...)). Read outcome before reading the text. It never flips success, partial / blocked results are not cached, and a dispatch_parallel(..., aggregate=...) labels such members for the aggregator so a blocked report is not synthesized as a finished one. Absent when the agent did not report one — the protocol is off (settings.dispatch_protocol: false), response_format="json" was requested (the JSON footer governs the reply shape there), or the agent simply skipped it.
Startup cost. Each dispatch is a fresh claude session, and a session's preamble — the project's CLAUDE.md, the skill listing, MCP server instructions and tool names — is written to the prompt cache again for every new task text (the task sits in front of it, so two different tasks share none of it). Measured on claude 2.1.322 in a gateway directory: ~32k tokens per dispatch before the agent does anything, which is most of what a short run costs. Two opt-in per-agent switches trim it — agent-dispatch update <name> --no-skills (no skill/command listing, user-level skills included: −27% in that measurement) and --strict-mcp (only the directory's own .mcp.json, no user-scope servers or connectors: −11%; the agent then cannot dispatch others, and loses any tool it got from a user-scope server). Check what an agent actually uses before turning either on; --skills / --no-strict-mcp undo them. A follow-up to the same agent is the opposite case: dispatch_session with the session_id from the previous result re-reads that preamble from cache (measured: $0.005–0.017 per follow-up against $0.089 for a fresh dispatch), so continue a session rather than re-dispatching when the question builds on the last answer. The larger levers stay outside this tool: a cheaper model for gateway agents and a shorter agent CLAUDE.md.
Standing orders. Per-agent instructions (set via add_agent / update_agent or agent-dispatch update <name> --instructions "...") follow the protocol in the same system prompt on every dispatch — "read-only SQL only", "never restart a stack unless the task says so", "answer with exact log lines". Unlike context, which is per call, and unlike the project's own CLAUDE.md, which is written for an interactive session, these are the rules for being dispatched.
// Response (success, but the agent says it did not finish)
{
"agent": "infra",
"success": true,
"result": "Restarted horizon. Could not verify the queue drained: the redis container is not reachable from here.",
"session_id": "sess-abc-123",
"outcome": "partial",
"hint": "The agent reports its work is PARTIAL — read the result for what is missing, then continue in the same session via dispatch_session(agent='infra', task='Continue where you left off', session_id='sess-abc-123') or re-dispatch with what it needed."
}
dispatch_session
Multi-turn: continue a conversation with an agent. First call starts a session, pass session_id back to continue. Never cached.
| Parameter | Type | Required | Description |
|---|---|---|---|
agent |
string | yes | Agent name |
task |
string | yes | Task or follow-up message |
session_id |
string | no | From previous response — empty for new session |
context |
string | no | Extra context |
caller |
string | no | Who is dispatching |
goal |
string | no | Broader objective |
timeout_seconds |
int | no | One-off timeout override (0 = agent default; clamped to 10–7200) |
dispatch_session is also the timeout recovery path: a timed-out dispatch returns a session_id — pass it here with task="Continue where you left off" to salvage the partial work instead of restarting.
Turn 1: dispatch_session("infra", "List running containers")
→ session_id: "sess-abc"
Turn 2: dispatch_session("infra", "Restart the nginx one", session_id="sess-abc")
→ agent remembers previous context
dispatch_parallel
Run multiple tasks concurrently. Much faster than sequential dispatch calls.
| Parameter | Type | Required | Description |
|---|---|---|---|
dispatches |
string (JSON) | yes | JSON array of {"agent", "task", "context?", "caller?", "goal?", "response_format?", "return_ref?", "summary_chars?", "timeout_seconds?", "group?"} (a per-item group validates membership up front and auto-injects its shared_context) |
aggregate |
string | no | Agent name to synthesize all results into one answer |
Important: dispatches is a JSON string, not a list.
// Input
[
{"agent": "infra", "task": "check pod logs for errors", "caller": "backend", "goal": "debug crash"},
{"agent": "db", "task": "are all migrations applied?", "caller": "backend", "goal": "debug crash"}
]
// Response (without aggregate)
[
{"agent": "infra", "success": true, "result": "No errors in pod logs", ...},
{"agent": "db", "success": true, "result": "All migrations applied", ...}
]
// Response (with aggregate="backend")
{
"individual_results": [
{"agent": "infra", "success": true, "result": "No errors in pod logs", ...},
{"agent": "db", "success": true, "result": "All migrations applied", ...}
],
"aggregated": {
"agent": "backend",
"success": true,
"result": "Summary: all systems nominal. No pod errors, all migrations applied."
}
}
dispatch_stream
Same as dispatch but shows live progress while the agent works. Use for long-running tasks. Not cached.
Progress notifications keep the latest 100 pending messages, capped at 300 characters each. If output arrives faster than the client can receive it, older notifications are omitted with a count; the final result is unaffected. Disconnecting or cancelling the tool call discards pending notifications and stops buffering new ones. The worker still holds its concurrency slot until it finishes.
Parameters are the same as dispatch except return_ref/summary_chars (streaming is incompatible with ref-mode) and group (group context injection is supported only on dispatch and per-item in dispatch_parallel).
dispatch_dialogue
Two agents collaborate through multi-turn conversation. Never cached.
| Parameter | Type | Required | Description |
|---|---|---|---|
requester |
string | yes | Agent with the problem/context |
responder |
string | yes | Agent with the expertise/tools |
topic |
string | yes | Problem or question to discuss |
max_rounds |
int | no | Max back-and-forth rounds (default: 3, max: 10) |
Each round costs up to 2 dispatches. Agents signal completion with [RESOLVED].
// Response
{
"resolved": true,
"rounds": 2,
"total_cost_usd": 0.04,
"total_duration_ms": 12000,
"final_answer": "Staging had 1 pending migration. Applied successfully.",
"conversation": [
{"agent": "db", "role": "responder", "round": 1, "message": "Which environment?", "cost_usd": 0.01},
{"agent": "backend", "role": "requester", "round": 1, "message": "Staging", "cost_usd": 0.01},
{"agent": "db", "role": "responder", "round": 2, "message": "Applied. [RESOLVED]", "cost_usd": 0.01}
]
}
add_agent
Register a new project directory as an agent. Description is auto-generated from project files if omitted.
| Parameter | Type | Required | Description |
|---|---|---|---|
name |
string | yes | Agent name (letters, digits, hyphens, underscores) |
directory |
string | yes | Path to an existing project directory (~ is expanded, relative paths resolved) |
description |
string | no | What this agent can do — auto-generated if empty |
timeout |
int | no | Timeout in seconds (0 = 300; this is a literal default, not settings.default_timeout) |
max_budget_usd |
float | no | Finite max cost in USD per dispatch (0 = inherit settings.default_max_budget_usd; no cap only when that is unset too) |
permission_mode |
string | no | Permission mode (e.g. default, plan, bypassPermissions) |
allowed_tools |
string | no | Comma-separated allowed tools (e.g. "Bash,Read,Edit") |
disallowed_tools |
string | no | Comma-separated disallowed tools |
capabilities |
string | no | Comma-separated capability labels (e.g. "docker_logs,deploy_debug") |
risky_capabilities |
string | no | Comma-separated high-risk labels (e.g. "restart_services") |
instructions |
string | no | Standing orders appended to the agent's system prompt on every dispatch (see the dispatch protocol) |
agent-dispatch MCP 질문
agent-dispatch MCP는 어떤 도구를 제공하나요?
5개 도구를 제공합니다. 예: name, preview_lines, description, shared_context, agent.
새로운 에이전트를 등록하려면 어떻게 해야 하나요?
agent-dispatch add <name> <path> 명령어를 사용하여 프로젝트 디렉토리를 에이전트로 등록할 수 있습니다.
테스트 중 권한 오류가 발생하면 어떻게 해야 하나요?
agent-dispatch update <name> --allowed-tools "Bash,Read,Grep"와 같이 update 명령어를 사용하여 특정 도구에 대한 액세스 권한을 부여하거나, bypass 모드를 사용하여 모든 권한을 사용할 수 있습니다.