From 3afea26ac5abb03f315ea13df63c471a1ce021b4 Mon Sep 17 00:00:00 2001 From: Brad Harris Date: Thu, 20 Aug 2026 22:05:32 -0600 Subject: [PATCH] Correct the Repo Tools manifest-failure and scope claims MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A malformed .dispatch/tools.json entry throws out of loadRepoTools, which propagates through createDispatchMcpServer and out of the (already hijacked) MCP route — so the whole Dispatch MCP server fails for that session rather than just the repo_ tools going missing. Both docs-pane and the repo-tools SKILL.md described it as "repo_ tools disappear". parseRepoToolScope drops unrecognized scope entries and returns undefined when nothing is left, so a misspelled scope silently re-exposes a job-only tool to every agent. SKILL.md also still listed "reviewer" as a usable scope; routes/ mcp.ts only ever sets toolScope to "job" or "agent", so a tool scoped to "reviewer" alone reaches no one. api-spec said only agent-scoped MCP loads repo tools, from the agent's working directory. The job-scoped route loads them too, and both resolve the checkout root (worktree root, else repo root) from agent.cwd. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01KzXr7HNouFonD29oEpgwPr --- .../components/app/docs-sections/tools.tsx | 11 +++++--- docs/03-api-spec.md | 2 +- plugins/dispatch/skills/repo-tools/SKILL.md | 27 ++++++++++++------- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/apps/web/src/components/app/docs-sections/tools.tsx b/apps/web/src/components/app/docs-sections/tools.tsx index a6380880..9b5f4768 100644 --- a/apps/web/src/components/app/docs-sections/tools.tsx +++ b/apps/web/src/components/app/docs-sections/tools.tsx @@ -50,8 +50,10 @@ export function ToolsContent() { directly rather than through a shell, so pipes, globs, and{" "} && don't work — put anything shell-shaped in a script and point command at that. A malformed entry - aborts the whole manifest, so a typo in one tool makes every{" "} - repo_ tool disappear. + aborts the whole manifest, and that failure takes the MCP request with + it — so a typo in one tool doesn't just hide the repo_{" "} + tools, it leaves the session with no Dispatch tools at all until the + file is fixed.

@@ -131,7 +133,10 @@ export function ToolsContent() { scopes are "agent" (standard agents and persona reviewers) and "job" (scheduled job runs). Useful for job-only maintenance commands that shouldn't clutter a regular agent's - toolset. + toolset. Anything Dispatch doesn't recognize is dropped from the + array, and a scope left with nothing recognizable is + treated as no scope at all — so a typo quietly re-exposes the tool + everywhere.

{` { diff --git a/docs/03-api-spec.md b/docs/03-api-spec.md index d51a383c..dd088b12 100644 --- a/docs/03-api-spec.md +++ b/docs/03-api-spec.md @@ -694,7 +694,7 @@ These endpoints use the `/api/mcp` base path (not `/api/v1`). | POST | `/api/mcp/:agentId` | Handle agent-scoped MCP requests with repo context | | POST | `/api/mcp/jobs/:runId/:agentId` | Handle job-scoped MCP requests (adds job lifecycle tools) | -Agent-scoped MCP loads repo tools from `.dispatch/tools.json` in the agent's working directory. +Agent-scoped and job-scoped MCP both load repo tools from `.dispatch/tools.json` at the root of the agent's checkout — the worktree root when the agent has one, otherwise the repo root — resolved from `agent.cwd`. A tool's optional `scope` array decides which of the two routes exposes it (`agent` or `job`); the global `/api/mcp` route has no agent and loads none. ## Error Codes diff --git a/plugins/dispatch/skills/repo-tools/SKILL.md b/plugins/dispatch/skills/repo-tools/SKILL.md index 31b4ec4a..d4d0c7ad 100644 --- a/plugins/dispatch/skills/repo-tools/SKILL.md +++ b/plugins/dispatch/skills/repo-tools/SKILL.md @@ -50,18 +50,25 @@ it at the moment of use. ## Tool entries -| Field | Required | Notes | -| ------------- | -------- | --------------------------------------------------------------------------- | -| `name` | yes | Exposed as `repo_`. Dots are stripped — MCP names cannot contain them | -| `description` | yes | This is what makes the tool get used. See below | -| `command` | yes | Argv array, run from the agent's checkout root | -| `params` | no | Turned into CLI flags appended to `command` | -| `scope` | no | Any of `agent`, `reviewer`, `job`. Omit to expose everywhere | +| Field | Required | Notes | +| ------------- | -------- | ------------------------------------------------------------------------------------------------------------ | +| `name` | yes | Exposed as `repo_`. Dots are stripped — MCP names cannot contain them | +| `description` | yes | This is what makes the tool get used. See below | +| `command` | yes | Argv array, run from the agent's checkout root | +| `params` | no | Turned into CLI flags appended to `command` | +| `scope` | no | `agent` (standard agents and persona reviewers) and/or `job` (scheduled job runs). Omit to expose everywhere | `repo_` prefixing is automatic and keeps repo tools in their own namespace, so a repo tool can never shadow a built-in Dispatch tool like `create_pr` or `dispatch_event`. +Scope values Dispatch doesn't recognize are dropped from the array, and a `scope` +left with nothing recognizable falls back to no scope at all — so a misspelled +scope silently re-exposes a job-only tool to every agent. Older manifests +sometimes carry `"reviewer"`; nothing is ever loaded under that scope, so a tool +scoped to it alone is exposed to no one. Persona reviewers are covered by +`agent`. + **Write the description for an agent that has never seen this repo.** It is the only thing standing between the tool existing and the tool being used. Say what the command does and when to reach for it — not just what it is named. @@ -108,5 +115,7 @@ the server immediately, but a **newly added** tool usually will not be callable by an already-running agent until it reconnects or a new session starts. A malformed entry (missing `name`, `description`, or `command`) throws at load, -which surfaces as the repo's tools being absent rather than as a parse error. If -`repo_*` tools vanish, validate the JSON first. +and that error escapes the MCP request handler rather than being reported as a +parse error. The symptom is not "the `repo_*` tools are missing" — it is the +whole Dispatch MCP server failing for that session, built-in tools included. If +Dispatch's tools stop resolving, validate `.dispatch/tools.json` first.