# MCP Contract
Agents use MCP tools to log work and receive feedback. The server must enforce rules. Agent prompts are not enough.

## Install Paths

Co-Vibe exposes two agent paths:

- stdio MCP bridge: `npm exec -- covibe-mcp` in customer repos, or `npm run mcp:stdio` in this repo
- direct JSON endpoint: `/api/mcp`
- local companion setup/status, watch, and inbox flush: `npm exec -- covibe-local setup --base-url <origin>`, `npm exec -- covibe-local doctor --base-url <origin>`, `npm exec -- covibe-local watch --base-url <origin>`, then `npm exec -- covibe-local telemetry --base-url <origin> --inbox .covibe/telemetry`

Both paths expose the same task lifecycle tools, including plan, start planned, and cancel.

Claude Code uses the same stdio bridge through `.mcp.json`; `.claude/settings.json` starts/ends Co-Vibe sessions and forwards usage counters to `covibe_ingest_agent_telemetry`. When Cursor is installed, setup also writes a repo-local `.cursor/mcp.json` server entry and `.cursor/hooks.json` lifecycle hooks (see `cursor-integration.md`). The local companion installs those repo files, creates a `.covibe/telemetry` inbox for Codex/Cursor/provider usage JSON, syncs Codex Desktop split usage counters from local `response.completed` logs plus Cursor local usage, and verifies token, server, and hook readiness without storing the raw MCP token. Hosted customers point `COVIBE_BASE_URL` at the hosted app origin, install the companion package, and run `covibe-local setup` per repo for the agent config writes — there is no per-repo watch registration: agent activity registers each repo in `~/.covibe/repos.json` for the machine-level watcher. Setup rejects credential-bearing URLs, callback URLs, queries, hashes, and other paths. `covibe-local doctor` is a status alias for rechecking the installed repo without rewriting config.

Set these env vars for the stdio bridge:

- `COVIBE_BASE_URL`
- `COVIBE_MCP_TOKEN`

The stdio bridge injects the token into tool calls when the agent does not
pass one. When `COVIBE_MCP_TOKEN` is unset, the bridge and hooks fall back to
the typed per-agent token in `~/.covibe/credentials.json`, selected by the
non-secret `COVIBE_AGENT` config marker (see `device-setup.md`).

The Settings → Agent setup config includes the repo `cwd` so copied stdio
configs run outside the repository shell. The copied local setup block is
finite (install companion, prompt for `COVIBE_MCP_TOKEN`, run setup, run
`covibe-local doctor`, exit); setup installs the machine-level watch service by default (`--no-service` opts out), and the separate copyable `covibe-local watch` command runs the same loop in the foreground.
Watch reads only numeric usage counters from local
Codex and Cursor stores (`codex-integration.md`, `cursor-integration.md`);
without split counters no usage event is submitted. Prompts, responses,
transcripts, logs, and file contents stay local.

Agents should call `covibe_session` with `operation: "start"` at the start of
a long run (include `agent_name`, `provider`, and `model` when available),
pass the returned `session_id` into task/scope/blocker/decision/summary/usage
tools, heartbeat with `operation: "heartbeat"`, submit local repo state with
`operation: "snapshot"` for dirty files, unpushed files, diff hashes, recent
commits, and worktree/branch state (which feeds the per-repo local graph), and
end with `operation: "end"`. Snapshot overlap returns warnings to agents; tools
reject a `session_id` not owned by the developer attached to the token.

## Required Tools
The public MCP surface is compact and operation-based:

- `covibe_task`: `check`, `plan`, `start`, `start_planned`, `update`,
  `complete`, `cancel`
- `covibe_workstream`: `check`, `plan`, `start`, `start_planned`, `update`,
  `complete`, `cancel`
- `covibe_session`: `start`, `heartbeat`, `snapshot`, `activity`,
  `publish_context`, `get_context`, `revoke_context`, `end`
- `covibe_note`: `kind: "decision"` or `kind: "blocker"`
- `covibe_team`: `state`, `feedback`, `audit_parallel_work`,
  `generate_weekly_summary`
- `covibe_coordination`: announcements, code claims, peer asks/replies, handoffs, releases, conflict checks, and summaries
- `covibe_warning`: `dismiss`
- `covibe_ingest_agent_telemetry`

`covibe_team` with `operation: "generate_weekly_summary"` renders sections for
completed, planned, and active work, blockers, decisions, overlap warnings,
parallel audits, and agent sessions. The UI weekly summary route creates
summaries directly for the current developer and must not mint MCP tokens.
`covibe_team` with `operation: "feedback"` returns recent stored feedback
events for the calling developer.

`covibe_session` also carries the session context exchange (see
[`session-context.md`](./session-context.md)): `operation: "publish_context"`
upserts the caller's working context, superseding their previous active
context for the same repo/branch; `operation: "get_context"` returns a
teammate's latest active context by handle/id or lists all active workspace
contexts (never revoked, superseded, or expired rows; private developers
redacted like team state); `operation: "revoke_context"` withdraws an owned
context. Contexts expire after 24 hours by default (`ttl_hours` 1-168). A
coordination `operation: "handoff"` attaches the giver's active context
reference so the receiver can fetch it with `get_context`.

`covibe_team` with `operation: "state"` returns active team work, planned
work, recent completions, active workstreams, recent risks and decisions,
recent sessions, stale sessions, overlap warnings, published session contexts,
and next actions for the calling developer — `planned_work`,
`risks_decisions`, and `recent_completions` give agents context without
opening the dashboard. If stale sessions exist it returns `warning` and writes
an `agent_feedback_event` so agents review stale work before taking it over.
If the latest persisted parallel audit conflicts with active or blocked work
it also returns `warning` with `latest_parallel_audits` and
`parallel_audit_conflicts`; completed-vs-completed historical conflicts stay
visible but do not block agents.

`covibe_team` with `operation: "audit_parallel_work"` compares existing active,
blocked, and recently completed work. It returns `warning` when already-running
work appears duplicated or when active work repeats recently completed work.

The dashboard can run the same audit through `/api/audit` for the current signed-in developer without creating an MCP token.

The dashboard can also plan work directly: `/api/tasks` and `/api/workstreams`
are cookie-authenticated POST routes running the same overlap-checked planning
core as the MCP plan operations (developer-scoped, no MCP token). When the
check escalates candidates the route returns them with `requires_confirm` and
the console requires an explicit confirm — the same duplicate handling agents get.

Audit and coordination work events store bounded details in `payload_json` so agents and humans do not lose results after refresh.

Task and workstream `operation: "update"` only allows `active` or `blocked`
status updates on started work. On a PLANNED task, `operation: "update"` lets
the owner edit `title`, `description`, `scope`, `action`, `component`,
`priority`, and `task_type` before start; status stays `planned`, the edit
writes a `task.planned_updated` work event, and title/scope/description
changes re-embed the task. Field edits on started work return a warning.

Planned tasks are created with `covibe_task` `operation: "plan"`, shown in the
dashboard, and activated with `operation: "start_planned"`.

Planned workstreams mirror that lifecycle: `covibe_workstream`
`operation: "plan"` creates a `planned` workstream (`auto_created = 0`)
through the same overlap-checked path as a task plan;
`operation: "start_planned"` activates it after a recent check with the same
title; `operation: "cancel"` abandons an owned PLANNED workstream with a
reason (started workstreams still require `operation: "complete"`). They
appear in `/api/state` (`plannedWorkstreams`) and `covibe_team` state
(`planned_workstreams`), and are overlap candidates for other developers' checks.

Starting planned work requires a recent `covibe_task` `operation: "check"` call
with the same title and `planned_task_id` (workstreams: a recent
`covibe_workstream` `operation: "check"` with the same title). Both
`start_planned` operations then re-run overlap detection at activation time —
see the activation re-check section in [`mcp-overlap-contract.md`](./mcp-overlap-contract.md).

Completed tasks and workstreams cannot be updated or reopened through update tools.

Agents must use task/workstream `operation: "complete"` to finish work because
completion requires a result summary. On `covibe_task` `operation: "complete"`
the `summary` field is optional — `result_summary` is the canonical completion
text and doubles as the summary.

`covibe_workstream` `operation: "complete"` refuses to silently close a
workstream with open (planned/active/blocked) tasks: it returns a warning
listing `open_task_ids` and requires a `confirm_open_tasks: true` retry. The
confirmed `workstream.completed` event records those ids in its payload.

Agents can use `covibe_task` `operation: "cancel"` with a reason to abandon
owned planned, active, or blocked work. `covibe_workstream`
`operation: "cancel"` is planned-only. Repeated completion calls are
idempotent: they return `warning` and create no duplicate completion events.

Optional inputs: `feedback_type` (`warning|block|error|info`) and `limit` (1-100 rows).

`covibe_session` `operation: "heartbeat"` updates `last_seen_at` for an active session owned by the calling developer. `session_id` is optional — the machine companion heartbeats session-lessly to sync registered repos and report liveness, and passes one only to touch its own session. The optional `companion_version` drives the self-update handshake: with a hosted-companion manifest the response `data` carries `companion: { latest_version, tarball_sha256, update_available }`, where `update_available` is `latest_version !== companion_version` — convergence, so a machine ahead of its server updates back down (the companion self-updates from this answer, see `device-setup.md`). `companion_version` is server-untrusted input and is length-bounded (capped at 64 characters); an over-long value is rejected by the handler, the same way `registered_repos` is bounded. `operation: "end"` may only end an owned session; peer tokens get an error and no `session.ended` event. Sessions idle for more than 30 minutes render as `stale` in the dashboard and weekly summary.

`covibe_ingest_agent_telemetry` is the only usage-metric path. It accepts
structured Claude/Codex/OpenAI harness, provider, proxy, or OTel payloads,
parses model and token counters server-side, stores only counters plus a
SHA-256 payload hash, flags submitted-cost mismatches, and marks the span
`verified = 1`.

## Response Shape

Every tool returns:

```json
{
  "status": "ok",
  "message": "Short human-readable result.",
  "feedback": {
    "type": "info",
    "required_action": null
  },
  "data": {}
}
```

Malformed HTTP envelopes (invalid JSON, a non-object body, a missing `tool`
string) return `400` with the same structured error shape. Malformed
envelopes, unknown tools, and schema failures still write usage events.

The stdio bridge preserves structured API errors and converts unreachable,
hung, or non-JSON API failures into structured MCP text responses instead of
crashing or hanging the client process.

Blocked tools return:

```json
{
  "status": "blocked",
  "message": "Possible duplicate work found.",
  "feedback": {
    "type": "block",
    "required_action": "Ask the developer for confirmation and a reason before starting."
  },
  "data": {
    "warning_id": "warn_123",
    "matches": []
  }
}
```

## Check Before Start

`covibe_task` `operation: "start"` requires a recent successful `operation: "check"`.

`covibe_task` `operation: "plan"` logs future work without marking it active. If it overlaps existing work, the agent gets a warning and the warning is stored.

`covibe_task` `operation: "start_planned"` starts an owned planned task after `operation: "check"` confirms it is still safe to begin.

Task checks compare against planned, active, blocked, and recently completed work. Completed work older than the 14-day recent window is still visible in history but does not block a new start.

Task `check`/`plan`/`start` REQUIRE `task_type`
(`feature|bug|refactor|chore|docs|test|spike`) — no default; a missing or
unknown value fails schema validation in both the internal and public tool
schemas. `start_planned` takes no `task_type` (the planned row already stores
it), and a PLANNED task's owner can change it via `operation: "update"`.
Escalated candidates carry the candidate's `task_type` as informational
context; it never affects scoring, escalation, or blocking.

Task `check`/`plan`/`start` accept optional `target_files` (max 50
repo-relative paths), stored on the task as a SUPPORT signal:
`data.file_conflicts` lists intersections with other open tasks' targets and
recent snapshot dirty/unpushed files (source, owner, `same_developer`, shared
`files`, the other task's `action`); matching candidates carry `file_overlap`,
opposed work carries `action_divergent: true`. File conflicts inform — never
escalate or block; private developers redact to `@private`.

Task `operation: "plan"` and `operation: "start"` may include `workstream_id` to attach a task to an owned active or blocked workstream. Tasks cannot be attached to another developer's workstream or a completed workstream.

If a task omits `workstream_id`, the server assigns one: best matching owned open workstream in the workspace, else a new active auto-created workstream from the task title and scope/description. It writes `workstream.auto_created`, stores the id on `tasks.workstream_id`, and backfills older orphan tasks during schema initialization. Auto-created workstreams are containers: overlap and audit logic scores their tasks, not the generated container, and the server completes the container when no planned/active/blocked tasks remain inside it.

Starting overlapping planned work resolves its warning the same way as a direct task start: a v2 scope verdict writes `scope.judged`, a legacy confirmation writes `warning.confirmed`.

`covibe_workstream` `operation: "start"` requires a recent successful
`operation: "check"`. Recent means within 10 minutes.

If the check found overlap with still-live work, start requires the exact
`warning_id` returned by the latest check plus a `confirmation_reason`;
without those the tool returns `blocked` (carrying the warning's matches).
Matches whose work is all `done`/`cancelled` by start time never block: the
warning auto-dismisses and the start proceeds.

## Overlap Detection v2

The stage-2 agent-judge protocol lives in
[`mcp-overlap-contract.md`](./mcp-overlap-contract.md). In short, escalated
checks return `check_id`, `requires_verdict`, and candidates (with score and
reason); starts then require the matching `check_id` plus a `scope_verdict`,
and confirmed duplicates still need `confirmation_reason`. Weak warn-floor
warnings are disclosed on the check (`warning_id` + `data.matches`) but never
block a start — blocking is reserved for escalated and agent-confirmed paths.

## Agent Feedback

Warnings and blocks must be returned to the agent in the MCP response — it is
not enough to show the warning in the UI — and the response must tell the
agent what to do next.

## Logging

Every MCP call writes a `usage_event`; every successful state change writes a `work_event`.

These Activity events are written so work is visible before and after it
changes state: `task.checked` / `workstream.checked` (preflight and activation
re-checks), `task.planned` / `workstream.planned` (future work),
`task.planned_updated` (planned-task edits), `workstream.start_planned`
(planned workstream activation), `task.cancelled` / `workstream.cancelled`
(abandoned work), `weekly_summary.generated`, and `parallel_work.audit`
(duplicate-work reviews).

When `session_id` is provided, usage and work events link to that agent session.

Rejected foreign-session attempts write an error usage event without linking that usage or work to the foreign session.

Blocked calls also write a `usage_event`; warnings and blocks also write an `agent_feedback_event`.

A resolved agent scope verdict writes a `scope.judged` work event
(`payload.duplicate` true when a duplicate was confirmed). A legacy
confirmation override writes a `warning.confirmed` event.

Agents can later retrieve stored feedback with `covibe_team`
`operation: "feedback"`.

## Authentication

Every MCP call must include a developer token; the server maps it to a developer.
Store only token hashes. Revoked tokens must fail.

Tokens may carry a typed `agent_type` (`claude-code`, `codex`, `cursor`). A
typed token's type overrides the agent's self-reported `agent_type` at
`covibe_session` start; an explicit conflicting report writes a
`session.agent_mismatch` work event. The device-flow setup mints one typed
token per agent (`device-setup.md`).

The UI can create and revoke MCP tokens for the current developer. UI-created
tokens receive distinct default labels for safer inventory management. Token
creation and revocation write Activity work events without raw token values.

Every mutating tool is owner-scoped to the developer attached to the MCP token:
task update/complete, decision/blocker attach, workstream update/complete, and
session heartbeat/end all reject ids owned by another developer.
