Documentation
¶
Overview ¶
Package mcp is the `brigada mcp` bridge (design §12.2): a stdio MCP server the foreman's harness starts, which offers brigada's tools by calling the engine API with the lease-scoped foreman token (§12.1). The foreman decides; the engine enforces (§1) — the bridge holds no state and no judgment of its own, it only renders what the engine answers.
The protocol is newline-delimited JSON-RPC 2.0 over stdin and stdout: stdout carries protocol messages and nothing else, logs go to stderr alone, and one malformed line is a parse error the server answers and survives. The token never rides a flag — flags are public to anyone listing processes — but the BRIGADA_TOKEN environment variable the runner names in the harness's MCP config (HarnessConfig).
Index ¶
Constants ¶
const EnvToken = "BRIGADA_TOKEN"
EnvToken is the environment variable the bridge reads its engine token from (§12.2): never a flag — flags are public to anyone listing processes. The harness's MCP config names it in the server's env, which the harness passes to the bridge process alone. Codex takes no env values on its command line either: it gets the token in its own process environment and forwards it to the bridge by name (env_vars).
const ServerName = "brigada"
ServerName is the bridge's name as the harness's config offers it (§12.2) and initialize reports it: the one MCP server a foreman turn carries, `brigada`.
Variables ¶
var ClientTools = []Tool{ { Name: "ask_foreman", Description: "Send the project's foreman a message as the user (a request: plan this, fix that, what is blocking task 3?). With nobody attached to the foreman, it wakes up and acts on it; otherwise the message waits for the attached chat. The answer says which happened and gives the message's id. Follow the work with status and history. The same text again within a day counts as a retry of the first call; reword it to send it anew.", InputSchema: map[string]any{ "type": "object", "properties": map[string]any{ "text": map[string]any{ "type": "string", "description": "the message, as the user would write it to the foreman", }, "repo_url": map[string]any{ "type": "string", "description": "the project's repo URL; omit when the engine has one project", }, }, "required": []string{"text"}, }, Call: callAskForeman, }, { Name: "status", Description: "The engine's state across every project: the running jobs with each worker's latest event, the plans with their tasks and branches, the foreman's latest report, messages still waiting for the foreman, and the \"needs you\" queue. The plans list keeps every live plan and the three most recently finished ones; the older finished plans are counted in one summary line — pass all=true to list every finished plan.", InputSchema: map[string]any{ "type": "object", "properties": map[string]any{ "all": map[string]any{ "type": "boolean", "description": "list every finished plan, not only the three most recent; the default counts the older ones in one summary line", }, }, }, Call: callStatus, }, { Name: "history", Description: "The timeline — events and messages merged, oldest first — optionally one task's, at most `limit` items: what the foreman planned, what each worker did and said, reviews, reports.", InputSchema: map[string]any{ "type": "object", "properties": map[string]any{ "task": map[string]any{ "type": "integer", "description": "show one task's timeline only", }, "limit": map[string]any{ "type": "integer", "description": "how many items to show, 1..500 (default 100)", }, }, }, Call: callHistory, }, }
ClientTools is the client bridge's offer (§12.2, proposal 2026-10-14): `brigada mcp --client`, for any harness acting for the user — a coding session, a coordinator — so it can talk to the foreman and watch the work without a person relaying between the two. It bears the client token, never a foreman token: it can send the user's message, read the status and read the history, and nothing a foreman does.
var CoordinatorTools = []Tool{ { Name: "list_projects", Description: "Every project the engine knows, by canonical repo URL: its foreman, its active plans and how many things need the user. Name a project in the other tools by this URL.", InputSchema: map[string]any{ "type": "object", "properties": map[string]any{}, }, Call: callListProjects, }, { Name: "ask_foreman", Description: "Send one project's foreman a message as the user (a request: plan this, fix that, what is blocking task 3?). One request per project: a cross-project plan does not exist, so send each project its own message. With nobody attached to the foreman, it wakes up and acts on it; otherwise the message waits for the attached chat. Follow the work with status and history. The same text again within a day counts as a retry of the first call; reword it to send it anew.", InputSchema: map[string]any{ "type": "object", "properties": map[string]any{ "repo_url": map[string]any{ "type": "string", "description": "the project's canonical repo URL, as list_projects shows it", }, "text": map[string]any{ "type": "string", "description": "the message, as the user would write it to the foreman", }, }, "required": []string{"repo_url", "text"}, }, Call: callCoordinatorAsk, }, { Name: "status", Description: "The engine's state: the running jobs with each worker's latest event, the plans with their tasks, messages still waiting for a foreman and the \"needs you\" queue, with each plan awaiting approval named with its id, version and why it waits (its tasks sit in the plans section). The plans list keeps every live plan — active or awaiting approval — and the three most recently finished ones; the older finished plans are counted in one summary line — pass all=true to list every finished plan. Across every project, or for one with repo_url.", InputSchema: map[string]any{ "type": "object", "properties": map[string]any{ "repo_url": map[string]any{ "type": "string", "description": "one project's canonical repo URL; omit for every project", }, "all": map[string]any{ "type": "boolean", "description": "list every finished plan, not only the three most recent; the default counts the older ones in one summary line", }, }, }, Call: callCoordinatorStatus, }, { Name: "history", Description: "The timeline — events and messages merged, oldest first — across every project, or one project's with repo_url, optionally one task's, at most `limit` items.", InputSchema: map[string]any{ "type": "object", "properties": map[string]any{ "repo_url": map[string]any{ "type": "string", "description": "one project's canonical repo URL; omit for every project", }, "task": map[string]any{ "type": "integer", "description": "show one task's timeline only", }, "limit": map[string]any{ "type": "integer", "description": "how many items to show, 1..500 (default 100)", }, }, }, Call: callCoordinatorHistory, }, { Name: "plan_approve", Description: "Approve a plan awaiting approval: its first wave of work starts. This is the USER's decision, never yours: call it only after you showed the user the plan (status shows it) and they said an explicit yes in this chat. \"Awaiting approval\" is a result to present, not a permission. Name the plan's id and the version you showed; a plan amended since is refused, then read status again and show it anew. With and_stop_asking true, the approval also changes the rule that held the plan — the one setting each hold reason maps to — the way `brigada project set` would, so the same question is not asked twice; use it only when the user said to change the rule, and show them what changed.", InputSchema: planDecisionSchema, Call: callPlanApprove, }, { Name: "plan_reject", Description: "Reject a plan awaiting approval: its tasks are cancelled and its foreman hears of it. This is the USER's decision, never yours: call it only after you showed the user the plan and they said an explicit no (or asked to drop it) in this chat. Name the plan's id and the version you showed; a plan amended since is refused, then read status again and show it anew.", InputSchema: planDecisionSchema, Call: callPlanReject, }, }
CoordinatorTools is the coordinator bridge's offer (§12.2, §4.6 mode B): `brigada mcp --coordinator`, a session over several projects. It bears the client token, never a foreman credential. It talks to each project's foreman and reads across projects, and it carries the user's decision on a plan — and nothing that plans or edits: no plan_create, no plan_amend, no task mutation and no hold tool.
Functions ¶
func AskOutcomeLine ¶
AskOutcomeLine says in one line what a user message did (§4.2 item 3): the foreman woke for it, or why it waits — never a silent queue. The CLI's ask prints the same line.
func CoordinatorToolNames ¶
func CoordinatorToolNames() []string
CoordinatorToolNames lists the coordinator's tools by name.
func HarnessConfig ¶
HarnessConfig renders the harness's MCP config for one foreman turn (§12.2): one server, `brigada` — the command the runner names (its own binary, os.Executable) run as `mcp --socket <socket>`, with the lease-scoped foreman token in the environment under EnvToken. The runner writes the bytes to a private file and deletes it when the turn ends; the token reaches the file and the bridge alone.
Types ¶
type Server ¶
type Server struct {
// Client reaches the engine (§12.1); its token is the lease-scoped
// foreman token, so every call is already scoped to the turn's
// project and dies with the turn's lease.
Client *api.Client
// Log is where the bridge's own notes go: stderr, never stdout —
// stdout is the protocol's alone. Nil discards them.
Log *slog.Logger
// Tools is the offer: nil is the foreman's tools (§12.2); the client
// bridge passes ClientTools.
Tools []Tool
}
Server is the bridge (§12.2): the engine's API client — bearing the turn's foreman token — behind the MCP protocol. The zero value is not usable; Client is required, Log is optional and writes to stderr.
type Tool ¶
type Tool struct {
Name string
Description string
// InputSchema is the tool's JSON Schema object: an object type whose
// properties are the tool's arguments.
InputSchema any
// Call runs the tool. An error is the tool's own answer — isError
// with the message (§12.2) — never the bridge's death.
Call func(ctx context.Context, c *api.Client, args json.RawMessage) (string, error)
}
Tool is one of the foreman's MCP tools (§12.2): its name and description as tools/list shows them, the JSON schema of its arguments, and its call — the engine reached through the API client the server bears, the answer rendered as text. A tool renders; it never judges (§1).