RFC-MACP-0006
RFC-MACP-0006
Multi-Agent Coordination Protocol (MACP) — Transport Bindings
Document: RFC-MACP-0006 Version: 1.1.0-draft Status: Community Standards Track Updates: RFC-MACP-0001
Changelog — 1.1.0-draft: passive session subscription is promoted from the former Appendix A.1 to core
StreamSessionsemantics in §3.2.subscribe_session_idandafter_sequenceare normative on every runtime that advertisessessions.stream = true; they are not an optional capability.
1. Introduction
MACP is transport-agnostic. This document defines standard transport bindings for MACP messages.
Normative transport: gRPC over HTTP/2.
See RFC-MACP-0001 Section 9 for core transport requirements. For discovery of transport endpoints in manifests, see RFC-MACP-0005.
Registered transport identifiers are listed in registries/transports.md.
2. Envelope Transmission
All transports MUST carry canonical MACP Envelopes defined in RFC-MACP-0001.
Transport bindings MUST preserve:
- within-session acceptance order,
- idempotency semantics,
- session isolation,
- structured error signaling appropriate to the transport.
3. gRPC Binding (Normative)
Conformant implementations MUST support the gRPC binding.
The canonical gRPC service is defined in schemas/proto/macp/v1/core.proto. The proto file is the authoritative source; the listing below is reproduced for convenience.
service MACPRuntimeService {
rpc Initialize(InitializeRequest) returns (InitializeResponse);
rpc Send(SendRequest) returns (SendResponse);
rpc StreamSession(stream StreamSessionRequest) returns (stream StreamSessionResponse);
rpc GetSession(GetSessionRequest) returns (GetSessionResponse);
rpc CancelSession(CancelSessionRequest) returns (CancelSessionResponse);
rpc GetManifest(GetManifestRequest) returns (GetManifestResponse);
rpc ListModes(ListModesRequest) returns (ListModesResponse);
rpc WatchModeRegistry(WatchModeRegistryRequest) returns (stream WatchModeRegistryResponse);
rpc ListRoots(ListRootsRequest) returns (ListRootsResponse);
rpc WatchRoots(WatchRootsRequest) returns (stream WatchRootsResponse);
// Extension mode lifecycle
rpc ListExtModes(ListExtModesRequest) returns (ListExtModesResponse);
rpc RegisterExtMode(RegisterExtModeRequest) returns (RegisterExtModeResponse);
rpc UnregisterExtMode(UnregisterExtModeRequest) returns (UnregisterExtModeResponse);
rpc PromoteMode(PromoteModeRequest) returns (PromoteModeResponse);
// Ambient Signal observation
rpc WatchSignals(WatchSignalsRequest) returns (stream WatchSignalsResponse);
// Session lifecycle observation (RFC-MACP-0001 §7.3)
rpc ListSessions(ListSessionsRequest) returns (ListSessionsResponse);
rpc WatchSessions(WatchSessionsRequest) returns (stream WatchSessionsResponse);
// Governance policy lifecycle (RFC-MACP-0012)
rpc RegisterPolicy(RegisterPolicyRequest) returns (RegisterPolicyResponse);
rpc UnregisterPolicy(UnregisterPolicyRequest) returns (UnregisterPolicyResponse);
rpc GetPolicy(GetPolicyRequest) returns (GetPolicyResponse);
rpc ListPolicies(ListPoliciesRequest) returns (ListPoliciesResponse);
rpc WatchPolicies(WatchPoliciesRequest) returns (stream WatchPoliciesResponse);
}3.1 Send
Send is the authoritative per-message request/ack surface.
A compliant runtime MUST use SendResponse.ack for standard per-message acceptance or rejection signaling.
3.2 StreamSession
StreamSession is an optional interactive envelope stream advertised by sessions.stream.
A runtime that advertises sessions.stream = true MUST implement StreamSession with these semantics:
- the stream carries canonical MACP Envelopes only,
- once the stream is bound to a non-empty
session_id, all subsequent session-scoped envelopes on that stream MUST use the samesession_id, - accepted envelopes emitted by the server MUST appear in authoritative acceptance order for that session,
- the stream MUST NOT invent ad-hoc pseudo-envelopes (informal messages that are not canonical MACP Envelopes) whose payloads encode JSON-only acks or errors unless an explicitly negotiated experimental capability allows it.
StreamSession is not the standard replacement for unary Send acknowledgements. Clients that require standard per-message negative acknowledgements SHOULD use Send.
A runtime MAY echo back accepted client-submitted envelopes on the stream as part of the authoritative accepted sequence.
Session-scoped Signal envelopes are invalid in the base protocol and MUST NOT be used as a stream-attach mechanism. Clients that need zero-mutation observation of an existing session MUST use the passive session subscription semantics defined below.
Passive Session Subscription
StreamSessionRequest carries two session-binding shapes:
envelope— a session-scoped coordination envelope. StandardStreamSessionbehavior as specified above.subscribe_session_id(with optionalafter_sequence) — a passive-subscribe frame that binds the stream to an existing session's broadcast without emitting a coordination message.
A single StreamSessionRequest MUST NOT set both envelope and subscribe_session_id; a runtime MUST reject such a request as an invalid argument.
On a request with subscribe_session_id set, a runtime that advertises sessions.stream = true MUST:
- Authorize the caller. The caller MUST be an authenticated declared participant of the session, or an observer identity admitted by deployment policy (RFC-MACP-0004 §4). Unauthorized callers MUST be rejected.
- Replay accepted session envelopes in strict acceptance order starting from
after_sequence + 1. Whenafter_sequence = 0, replay begins at the session's first accepted envelope. - Switch seamlessly to live broadcast on the same stream after replay drains, preserving within-session acceptance order.
- Never replay rejected envelopes (RFC-MACP-0001 §7.2); only accepted-history envelopes are delivered.
A stream opened with a passive-subscribe frame is conventionally read-only. Implementations MAY refuse subsequent envelope frames on such a stream; clients that intend to coordinate on the session SHOULD open a separate StreamSession or use unary Send.
When a transport-level or stream-fatal error occurs, the runtime SHOULD use native gRPC stream termination semantics.
3.3 WatchModeRegistry and WatchRoots
These watch streams are optional discovery hints.
ListModes SHOULD return only standards-track mode descriptors. Extension mode descriptors are discoverable through implementation-defined surfaces and are not part of the base ListModes response.
A runtime MUST advertise mode_registry.list_changed = true before WatchModeRegistry can be assumed interoperable.
A runtime MUST advertise roots.list_changed = true before WatchRoots can be assumed interoperable.
A watch notification indicates that the corresponding registry or roots view may have changed. Clients SHOULD re-query the full surface (ListModes or ListRoots) after receiving a change notification. A minimal compliant implementation MAY send an initial change hint immediately after stream establishment and then remain idle until a later change occurs.
3.4 WatchSignals
WatchSignals is an optional server-streaming RPC that broadcasts Ambient Signal Envelopes to all subscribers.
Signals are non-binding messages on the ambient plane (per RFC-MACP-0001 §5.1). They MUST carry empty session_id and empty mode in the Envelope. Signals MUST NOT enter any session's accepted history or mutate session state.
A WatchSignalsResponse contains the full Envelope of each accepted Signal. The SignalPayload within the envelope MAY include a correlation_session_id to indicate which session the signal relates to, without making the Signal session-scoped.
Use cases include:
- progress notifications from agents working on evaluations
- heartbeat and liveness signals
- status updates between coordination steps
A runtime that supports WatchSignals MUST broadcast all accepted Signal envelopes to all active subscribers. Signals are ephemeral — they are not persisted and are not available for replay.
3.5 GetSession
GetSession returns a SessionMetadata snapshot for the given session. The response includes the session's identity, state, timing, and bound version fields (mode_version, configuration_version, policy_version), as well as the current participant list, per-participant activity summaries (ParticipantActivity), context_id (if set at session creation), and extension_keys (the keys of any extension blocks bound at session creation). The ParticipantActivity entries provide participant_id, last_message_at_unix_ms, and message_count for each participant that has sent at least one accepted message.
3.6 Extension Mode Lifecycle RPCs
ListExtModes, RegisterExtMode, UnregisterExtMode, and PromoteMode manage the lifecycle of non-standards-track (extension) coordination modes. These RPCs are implementation-defined surfaces for registering, discovering, and promoting experimental modes. See RFC-MACP-0002 for extension mode semantics and the relationship between extension and standards-track modes.
3.8 Session Lifecycle Observation RPCs
ListSessions and WatchSessions provide programmatic session lifecycle observation.
rpc ListSessions(ListSessionsRequest) returns (ListSessionsResponse);
rpc WatchSessions(WatchSessionsRequest) returns (stream WatchSessionsResponse);ListSessions returns SessionMetadata for all currently known sessions (active and terminal). A runtime MUST advertise sessions.list_sessions = true before ListSessions can be assumed interoperable.
WatchSessions is a server-streaming RPC that emits SessionLifecycleEvent notifications. Each event carries an EventType (CREATED, RESOLVED, or EXPIRED), the affected SessionMetadata, and an observed_at_unix_ms timestamp. A runtime MUST advertise sessions.watch_sessions = true before WatchSessions can be assumed interoperable.
Session lifecycle events are ephemeral — they are not persisted and are not available for replay. Clients that disconnect MAY miss events. Control-planes and UIs SHOULD use ListSessions for initial sync and WatchSessions for incremental updates.
3.7 Policy Lifecycle RPCs
Five RPCs manage the governance policy lifecycle (see RFC-MACP-0012):
rpc RegisterPolicy(RegisterPolicyRequest) returns (RegisterPolicyResponse);
rpc UnregisterPolicy(UnregisterPolicyRequest) returns (UnregisterPolicyResponse);
rpc GetPolicy(GetPolicyRequest) returns (GetPolicyResponse);
rpc ListPolicies(ListPoliciesRequest) returns (ListPoliciesResponse);
rpc WatchPolicies(WatchPoliciesRequest) returns (stream WatchPoliciesResponse);RegisterPolicy and UnregisterPolicy mutate the policy registry. GetPolicy and ListPolicies are read-only queries. WatchPolicies is a server-streaming RPC for policy registry change notifications.
See RFC-MACP-0012 Section 7 for registration constraints and evaluation semantics.
4. HTTP Binding
The HTTP binding is OPTIONAL. Implementations providing it MUST preserve Envelope semantics and MUST map error codes to HTTP status codes per the error-codes registry.
Example endpoints:
POST /macp/envelope
POST /macp/session/start
GET /macp/session/{id}
POST /macp/session/{id}/cancel
GET /.well-known/macp.json5. WebSocket Binding
The WebSocket binding is OPTIONAL. Implementations providing it MUST frame each Envelope as a single WebSocket message and MUST preserve per-session ordering.
6. Message Bus Binding
The message bus binding is OPTIONAL. Implementations providing it MUST preserve per-session message ordering and MUST define how authoritative acceptance is established.
Example topics:
macp.signals
macp.sessions.{session_id}Possible systems:
- Kafka
- NATS
- RabbitMQ
7. Transport Selection
Implementations MUST support at least the gRPC binding. Additional transports are OPTIONAL.
- gRPC -- high throughput coordination
- HTTP -- simple integrations
- WebSocket -- interactive coordination
- Message Bus -- distributed systems
8. Security
All transports MUST use encrypted transport. Authentication requirements follow RFC-MACP-0004.