# MCP Tool Contract Protocol version: `2025-03-26` Endpoint: `POST /mcp` Transport profile: stateless Streamable HTTP with JSON responses `initialize`, `ping`, and `tools/list` do not require credentials. Every `tools/call` requires `Authorization: Bearer …`. The server does not implement server-to-client SSE notifications in this MVP; `GET /mcp` returns `405`. ## Common rules - Every project-scoped call resolves the authenticated principal to one active membership. - Every mutation requires a stable `idempotency_key`. - Reusing a key with the same operation and canonical arguments replays the original response. Reusing it with different input returns `conflict`. - IDs use letters, numbers, `.`, `_`, `:`, `/`, or `-`, up to 128 characters. - Tool domain failures are MCP tool results with `isError: true`. - JSON-RPC syntax/method failures use JSON-RPC error objects. - Missing or invalid credentials return HTTP `401`. ## Tools | Tool | Allowed role / invariant | Primary event | |---|---|---| | `create_project` | SYSTEM only | `project.created` | | `register_actor` | SYSTEM, PO, PM; PM cannot appoint PO | `actor.registered` | | `issue_work_package` | PO, PM | `work_package.issued` | | `claim_work_package` | Architect, Lead Engineer, Implementer; atomic OPEN claim | `work_package.claimed` | | `submit_result` | claiming actor only | `work_package.result_submitted` | | `request_review` | PO, PM, PA, implementation/design roles; reviewer independent | `review.requested` | | `submit_review` | assigned independent review actor | `review.submitted` | | `record_decision` | product: PO; other kinds: PO/PM; never PA | `decision.recorded` | | `raise_escalation` | every active member | `escalation.raised` | | `resolve_escalation` | PO, PM | `escalation.resolved` | | `link_commit` | every active member; valid hexadecimal object ID | `commit.linked` | | `link_artifact` | every active member | `artifact.linked` | | `close_gate` | PO, PM; ACCEPT needs independent approval | `gate.closed` | | `baseline_release` | PO, PM; included work packages accepted | `baseline.released` | | `sync_since` | every active member; max 500 events | none | | `list_pending_actions` | every active member, role-filtered reviews/escalations | none | | `get_work_package` | every active member | none | | `get_project` | every active member; includes actor-role roster | none | The authoritative argument schema is returned by `tools/list`. Clients should discover it instead of hard-coding optional defaults. ## Event envelope `sync_since` returns: ```json { "cursor": 42, "event_id": "evt_...", "project_id": "example", "event_type": "review.submitted", "actor_id": "reviewer-1", "actor_role": "REVIEWER", "aggregate_type": "review", "aggregate_id": "rev_...", "correlation_id": "WP-001", "causation_event_id": null, "created_at": "2026-07-30T00:00:00.000Z", "payload": {} } ``` Event payloads are version-zero MVP structures. Consumers should ignore unknown fields and key behavior off `event_type`, not prose. ## MCP interoperability limits The transport implements the required request/response subset used by MCP tools over Streamable HTTP. It is stateless, does not issue `Mcp-Session-Id`, does not accept JSON-RPC batches, and provides no resumable SSE channel. Interoperability must be checked against the concrete ChatGPT and Claude Code clients during activation.